// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/.
/// Generates a pipeline-friendly string /// that replaces non alphanumeric characters with dashes. pubfn sanitize_application_id(application_id: &str) -> String { letmut last_dash = false;
application_id
.chars()
.filter_map(|x| match x { 'A'..='Z' | 'a'..='z' | '0'..='9' => {
last_dash = false;
Some(x.to_ascii_lowercase())
}
_ => { let result = if last_dash { None } else { Some('-') };
last_dash = true;
result
}
})
.collect()
}
/// Generates an ISO8601 compliant date/time string for the given time, /// truncating it to the provided [`TimeUnit`]. /// /// # Arguments /// /// * `datetime` - the [`DateTime`] object that holds the date, time and timezone information. /// * `truncate_to` - the desired resolution to use for the output string. /// /// # Returns /// /// A string representing the provided date/time truncated to the requested time unit. pubfn get_iso_time_string(datetime: DateTime<FixedOffset>, truncate_to: TimeUnit) -> String {
datetime.format(truncate_to.format_pattern()).to_string()
}
/// Get the current date & time with a fixed-offset timezone. /// /// This converts from the `Local` timezone into its fixed-offset equivalent. /// If a timezone outside of [-24h, +24h] is detected it corrects the timezone offset to UTC (+0). pub(crate) fn local_now_with_offset() -> DateTime<FixedOffset> { #[cfg(target_os = "windows")]
{ // `Local::now` takes the user's timezone offset // and panics if it's not within a range of [-24, +24] hours. // This causes crashes in a small number of clients on Windows. // // We can't determine the faulty clients // or the circumstancens under which this happens, // so the best we can do is have a workaround: // // We try getting the time and timezone first, // then manually check that it is a valid timezone offset. // If it is, we proceed and use that time and offset. // If it isn't we fallback to UTC. // // This has the small downside that it will use 2 calls to get the time, // but only on Windows. // // See https://bugzilla.mozilla.org/show_bug.cgi?id=1611770.
use chrono::Utc;
// Get timespec, including the user's timezone. let tm = time::now(); // Same as chrono: // https://docs.rs/chrono/0.4.10/src/chrono/offset/local.rs.html#37 let offset = tm.tm_utcoff; iflet None = FixedOffset::east_opt(offset) {
log::warn!( "Detected invalid timezone offset: {}. Using UTC fallback.",
offset
); let now: DateTime<Utc> = Utc::now(); let utc_offset = FixedOffset::east(0); return now.with_timezone(&utc_offset);
}
}
let now: DateTime<Local> = Local::now();
now.with_timezone(now.offset())
}
/// Truncates a string, ensuring that it doesn't end in the middle of a codepoint. /// /// # Arguments /// /// * `value` - The string to truncate. /// * `length` - The length, in bytes, to truncate to. The resulting string will /// be at most this many bytes, but may be shorter to prevent ending in the middle /// of a codepoint. /// /// # Returns /// /// A string, with at most `length` bytes. pub(crate) fn truncate_string_at_boundary<S: Into<String>>(value: S, length: usize) -> String { let s = value.into(); if s.len() > length { for i in (0..=length).rev() { if s.is_char_boundary(i) { return s[0..i].to_string();
}
} // If we never saw a character boundary, the safest thing we can do is // return the empty string, though this should never happen in practice. return"".to_string();
}
s
}
/// Truncates a string, ensuring that it doesn't end in the middle of a codepoint. /// If the string required truncation, records an error through the error /// reporting mechanism. /// /// # Arguments /// /// * `glean` - The Glean instance the metric doing the truncation belongs to. /// * `meta` - The metadata for the metric. Used for recording the error. /// * `value` - The String to truncate. /// * `length` - The length, in bytes, to truncate to. The resulting string will /// be at most this many bytes, but may be shorter to prevent ending in the middle /// of a codepoint. /// /// # Returns /// /// A string, with at most `length` bytes. pub(crate) fn truncate_string_at_boundary_with_error<S: Into<String>>(
glean: &Glean,
meta: &CommonMetricDataInternal,
value: S,
length: usize,
) -> String { let s = value.into(); if s.len() > length { let msg = format!("Value length {} exceeds maximum of {}", s.len(), length);
record_error(glean, meta, ErrorType::InvalidOverflow, msg, None);
truncate_string_at_boundary(s, length)
} else {
s
}
}
#[test] fn local_now_gets_the_time() { let now = Local::now(); let fixed_now = local_now_with_offset();
// We can't compare across differing timezones, so we just compare the UTC timestamps. // The second timestamp should be just a few nanoseconds later.
assert!(
fixed_now.naive_utc() >= now.naive_utc(), "Time mismatch. Local now: {:?}, Fixed now: {:?}",
now,
fixed_now
);
}
#[test] fn truncate_safely_test() { let value = "电脑坏了".to_string(); let truncated = truncate_string_at_boundary(value, 10);
assert_eq!("电脑坏", truncated);
let value = "0123456789abcdef".to_string(); let truncated = truncate_string_at_boundary(value, 10);
assert_eq!("0123456789", truncated);
}
#[test] #[should_panic] fn truncate_naive() { // Ensure that truncating the naïve way on this string would panic let value = "电脑坏了".to_string();
value[0..10].to_string();
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.