How to format datetime to show for example "5th of January 2020"?

Hello!

I have read through the documentation of datetime in typst here (Datetime Type – Typst Documentation) and gotten to this:

datetime.today().display("[day] of [month repr:long] [year]")

image

But how can I get it to do correctly, the 2nd, 3rd, 10th, 15th of a month etc. so it comes out as 5th of January 2020 for example?

Kind regards

You will have to manually find the appropriate suffix
Something like this should work for your needs

#let my-date(..args) = {
  let date = if args.pos().len() == 0 {
    datetime.today()
  } else {
    args.pos().first()
  }
  let day = date.day()
  let suffix = if day in (11, 12, 13) { "th" } else {
    ("st", "nd", "rd").at(calc.rem(day - 1, 10), default: "th")
  }
  date.display("[day padding:none]" + suffix + " of [month repr:long] [year]")
}
Today: #my-date()\
Custom date: #my-date(datetime(year: 2020, month: 1, day: 5))

EDIT: implemented Eric’s fix

1 Like

Watch out when determining the suffix, you currently have an off-by-one error at the start of the month, and wrong suffixes for 21, 22, 23 and 31 ;)

Something like this should do it

let suffix = if day in (11, 12, 13) { "th" } else {
  ("st", "nd", "rd").at(calc.rem(day - 1, 10), default: "th")
}
1 Like

:man_facepalming: :man_facepalming: :man_facepalming: indeed, thank you for your correction :sweat_smile:

This errors with 10 though:

my-date(datetime(year: 2020, month: 1, day: 10))

image

Any suggestions :) ?

EDIT: ChatGPT believes this to be a solution which works according to my test:

  let my_date(..args) = {
    // Determine the date, defaulting to today if no argument is provided.
    let date = if args.pos().len() == 0 {
      datetime.today()
    } else {
      args.pos().first()
    }
    
    // Calculate the day and determine the correct suffix.
    let day = date.day()
    let suffix = if day in (11, 12, 13) {
      "th"
    } else if calc.rem(day, 10) == 1 {
      "st"
    } else if calc.rem(day, 10) == 2 {
      "nd"
    } else if calc.rem(day, 10) == 3 {
      "rd"
    } else {
      "th"
    }

  // Display the formatted date.
  date.display("[day padding:none]" + suffix + " of [month repr:long] [year]")
}

Oops, you’re right, it should be calc.rem(day - 1, 10) instead of calc.rem(day, 10) - 1, I have edited my above reply. Your more explicit code by ChatGPT also works of course!

1 Like

Thank you Eric, I have used your fix with the solution provided above

Thank you to both of you! :)

May I suggest the nth package? :slight_smile:

then you don’t have to do this logic yourself:

#import "@preview/nth:1.0.1": *

#let my-date(date) = nth(date.day()) + date.display(" of [month repr:long] [year]")

Today: #my-date(datetime.today())\
Custom date: #my-date(datetime(year: 2020, month: 1, day: 5))

or replace nth with nths if you want superscript

3 Likes