Convert timestamps to relative times like '2 hours ago'
Generate relative time datelines at the Edge instead of in JavaScript or at origin. Better caching, faster rendering, fewer reflows.
VCL
Use this solution in your VCL service (click RUN below to test this solution or clone it to make changes):
Compute
Use this solution in your Compute service:
- Rust
Cargo.toml
Rust
[dependencies]fastly = "0.7.0"quick-xml = "0.20.0"
main.rs
Rust
use quick_xml::{ events::{BytesText, Event}, Reader, Writer,};use std::time::{Duration, UNIX_EPOCH};
fn parse_since(since: &str) -> String { match since.parse::<u64>() { Ok(secs) => { match (UNIX_EPOCH + Duration::from_secs(secs)) .elapsed() .map(|d| d.as_secs()) .unwrap_or(0) { n if n < 60 => format!("{}s ago", n), n if n < 3600 => format!("{}m ago", n / 60), n if n < 96 * 3600 => format!("{}h ago", n / 3600), n => format!("{}d ago", n / 86400), } } _ => "".to_string(), }}
#[fastly::main]fn main(mut req: Request) -> Result<Response, Error> { // Make sure the origin server does not gzip the response. We // can't process ESIs in gzipped content. req.remove_header(header::ACCEPT_ENCODING); let mut beresp = req.send("backend_name")?;
// This example only inspects HTML pages, but the same code could // be used in non-HTML content as well. match beresp.get_content_type() { Some(mime) if mime.essence_str() == "text/html" => return Ok(beresp), _ => (), }
let mut reader = Reader::from_reader(beresp.get_body_mut()); reader .trim_markup_names_in_closing_tags(false) .check_end_names(false); let mut writer = Writer::new(Body::new()); let mut buf = Vec::new(); loop { buf.clear(); match reader.read_event(&mut buf) { // We only handle ESI include here, but other ESI tags are possible. Ok(Event::Empty(elem)) if elem.name() == b"esi:include" => { if let Some(path) = elem.attributes().find_map(|attr| { if attr.as_ref().unwrap().key == b"src" { attr.unwrap().unescape_and_decode_value(&reader).ok() } else { None } }) { // We assume here that the source page's ESI includes are // in the form /__since/<unix-timestamp>, and we need to // convert that into a relative time. if let Some(since) = path.strip_prefix("/__since/") { writer.write_event(Event::Text(BytesText::from_escaped_str( parse_since(since), )))?; } } } Ok(Event::Eof) => break, Ok(e) => writer.write_event(&e)?, _ => {} } } Ok(beresp.with_body(writer.into_inner()))}
User contributed notes
BETADo you see an error in this page? Do have an interesting use case, example or edge case people should know about? Share your knowledge and help people who are reading this page! (Comments are moderated; for support, please contact support@fastly.com)