19 KiB
Time Format Patterns - Cross-System Comparison
Overview
This document provides a comprehensive comparison of time format patterns across different programming languages and systems. This research will help inform the design of a widely-recognized, human-readable time format.
1. Unicode LDML (Locale Data Markup Language)
Used by: ICU, Java, Swift, JavaScript (Intl), and many internationalization libraries
Key Characteristics
- Single letters represent minimal/numeric forms
- Repeated letters increase width or change format type
- Case-sensitive (different meanings for upper/lower case)
- Canonical order matters for skeletons
Format Tokens
| Element | Token | Examples | Notes |
|---|---|---|---|
| Year | |||
| 4-digit year | yyyy or y |
2024, 0070 | y adapts to context |
| 2-digit year | yy |
24, 70 | 00-99 |
| Month | |||
| Numeric, no zero | M |
1, 12 | 1-12 |
| Numeric, zero-padded | MM |
01, 12 | 01-12 |
| Abbreviated name | MMM |
Jan, Dec | Locale-specific |
| Full name | MMMM |
January, December | Locale-specific |
| Stand-alone abbrev | LLL |
Jan, Dec | Nominative form |
| Stand-alone full | LLLL |
January, December | Nominative form |
| Day of Month | |||
| Numeric, no zero | d |
1, 31 | 1-31 |
| Numeric, zero-padded | dd |
01, 31 | 01-31 |
| Weekday | |||
| Abbreviated | EEE |
Mon, Fri | Locale-specific |
| Full name | EEEE |
Monday, Friday | Locale-specific |
| Narrow | EEEEE |
M, F | Single character |
| Short | EEEEEE |
Mo, Fr | Between abbrev & narrow |
| Hour (12-hour) | |||
| No zero (1-12) | h |
1, 12 | Requires AM/PM |
| Zero-padded (01-12) | hh |
01, 12 | Requires AM/PM |
| Hour (24-hour) | |||
| No zero (0-23) | H |
0, 23 | |
| Zero-padded (00-23) | HH |
00, 23 | |
| Minute | |||
| No zero | m |
0, 59 | 0-59 |
| Zero-padded | mm |
00, 59 | 00-59 |
| Second | |||
| No zero | s |
0, 59 | 0-59 |
| Zero-padded | ss |
00, 59 | 00-59 |
| Fractional Seconds | |||
| Milliseconds | SSS |
000, 999 | Always 3 digits |
| Variable precision | S to SSSSSSSSS |
0 to 9 digits | Fractional precision |
| AM/PM | |||
| Period | a |
AM, PM | Locale-specific |
| Period, narrow | aaaaa |
a, p | Single character |
| Day period (flexible) | b |
at night, in the morning | Locale-specific |
| Day period (specific) | B |
noon, midnight | Locale-specific |
| Timezone | |||
| ISO offset | Z to ZZZZZ |
-0800, -08:00, Z | Various formats |
| Localized GMT | O to OOOO |
GMT-8, GMT-08:00 | |
| Generic non-location | v |
PT | Short form |
| Generic non-location | vvvv |
Pacific Time | Long form |
| Specific non-location | z |
PST | Short form |
| Specific non-location | zzzz |
Pacific Standard Time | Long form |
Common Pattern Examples
yyyy-MM-dd→ 2024-02-08MMM d, yyyy→ Feb 8, 2024EEEE, MMMM d, yyyy→ Thursday, February 8, 2024h:mm a→ 3:45 PMHH:mm:ss→ 15:45:30yyyy-MM-dd'T'HH:mm:ss→ 2024-02-08T15:45:30
2. strftime (C, Python, Ruby, PHP, etc.)
Used by: C, C++, Python, Ruby, PHP, Perl, Unix/Linux systems
Key Characteristics
- All format codes start with
% - Single character codes (case-sensitive)
- Platform-dependent for some codes
- Locale-aware variants with
EandOmodifiers
Format Codes
| Element | Code | Examples | Notes |
|---|---|---|---|
| Year | |||
| 4-digit year | %Y |
2024, 0070 | |
| 2-digit year | %y |
24, 70 | 00-99 |
| Century | %C |
20 | First 2 digits |
| Month | |||
| Numeric, zero-padded | %m |
01, 12 | 01-12 |
| Abbreviated name | %b or %h |
Jan, Dec | Locale-specific |
| Full name | %B |
January, December | Locale-specific |
| Day of Month | |||
| Zero-padded | %d |
01, 31 | 01-31 |
| Space-padded | %e |
" 1", "31" | 1-31 with space |
| Weekday | |||
| Abbreviated | %a |
Mon, Fri | Locale-specific |
| Full name | %A |
Monday, Friday | Locale-specific |
| Numeric (0-6) | %w |
0, 6 | Sunday = 0 |
| Numeric (1-7) | %u |
1, 7 | Monday = 1 |
| Hour (12-hour) | |||
| Zero-padded | %I |
01, 12 | 01-12, requires AM/PM |
| Hour (24-hour) | |||
| Zero-padded | %H |
00, 23 | 00-23 |
| Space-padded | %k |
" 0", "23" | 0-23 with space |
| Minute | |||
| Zero-padded | %M |
00, 59 | 00-59 |
| Second | |||
| Zero-padded | %S |
00, 59 | 00-59 |
| Fractional Seconds | |||
| Microseconds | %f |
000000, 999999 | Python-specific, 6 digits |
| AM/PM | |||
| Period | %p |
AM, PM | Locale-specific |
| Period lowercase | %P |
am, pm | GNU extension |
| Timezone | |||
| Name or abbreviation | %Z |
PST, EST | Platform-dependent |
| Offset | %z |
-0800, +0530 | ±HHMM format |
| Composite Formats | |||
| Date (MM/DD/YY) | %D |
02/08/24 | Equivalent to %m/%d/%y |
| ISO date | %F |
2024-02-08 | Equivalent to %Y-%m-%d |
| 12-hour time | %r |
03:45:30 PM | Locale-specific |
| 24-hour time (HH:MM) | %R |
15:45 | Equivalent to %H:%M |
| Time with seconds | %T |
15:45:30 | Equivalent to %H:%M:%S |
| Date and time | %c |
Thu Feb 8 15:45:30 2024 | Locale-specific |
Common Pattern Examples
%Y-%m-%d→ 2024-02-08%b %d, %Y→ Feb 08, 2024%A, %B %d, %Y→ Thursday, February 08, 2024%I:%M %p→ 03:45 PM%H:%M:%S→ 15:45:30%Y-%m-%dT%H:%M:%S→ 2024-02-08T15:45:30
3. Moment.js / Day.js (JavaScript)
Used by: Moment.js, Day.js (legacy JavaScript libraries)
Key Characteristics
- No special prefix character
- Case-sensitive
- Repetition changes format
- Inspired by PHP date() function
Format Tokens
| Element | Token | Examples | Notes |
|---|---|---|---|
| Year | |||
| 4-digit year | YYYY |
2024, 0070 | |
| 2-digit year | YY |
24, 70 | 00-99 |
| Month | |||
| Numeric, no zero | M |
1, 12 | 1-12 |
| Numeric, zero-padded | MM |
01, 12 | 01-12 |
| Abbreviated name | MMM |
Jan, Dec | |
| Full name | MMMM |
January, December | |
| Day of Month | |||
| Numeric, no zero | D |
1, 31 | 1-31 |
| Numeric, zero-padded | DD |
01, 31 | 01-31 |
| Ordinal | Do |
1st, 31st | With suffix |
| Weekday | |||
| Abbreviated | ddd |
Mon, Fri | |
| Full name | dddd |
Monday, Friday | |
| Min (2 chars) | dd |
Mo, Fr | |
| Numeric (0-6) | d |
0, 6 | Sunday = 0 |
| Hour (12-hour) | |||
| No zero (1-12) | h |
1, 12 | Requires A or a |
| Zero-padded (01-12) | hh |
01, 12 | Requires A or a |
| Hour (24-hour) | |||
| No zero (0-23) | H |
0, 23 | |
| Zero-padded (00-23) | HH |
00, 23 | |
| Minute | |||
| No zero | m |
0, 59 | 0-59 |
| Zero-padded | mm |
00, 59 | 00-59 |
| Second | |||
| No zero | s |
0, 59 | 0-59 |
| Zero-padded | ss |
00, 59 | 00-59 |
| Fractional Seconds | |||
| 1-3 digits | S, SS, SSS |
0, 00, 000 | Tenths, hundredths, ms |
| Up to 9 digits | SSSS to SSSSSSSSS |
Variable | Extended precision |
| AM/PM | |||
| Lowercase | a |
am, pm | |
| Uppercase | A |
AM, PM | |
| Timezone | |||
| Offset | Z |
-08:00, +05:30 | With colon |
| Compact offset | ZZ |
-0800, +0530 | Without colon |
Common Pattern Examples
YYYY-MM-DD→ 2024-02-08MMM D, YYYY→ Feb 8, 2024dddd, MMMM D, YYYY→ Thursday, February 8, 2024h:mm A→ 3:45 PMHH:mm:ss→ 15:45:30YYYY-MM-DDTHH:mm:ss→ 2024-02-08T15:45:30
4. date-fns (Modern JavaScript)
Used by: date-fns library
Key Characteristics
- Based on Unicode LDML tokens
- More standardized than Moment.js
- Case-sensitive
- Uses escape sequences for literals
Format Tokens
date-fns uses Unicode LDML tokens (see Section 1) with some differences:
| Element | Token | Examples | Notes |
|---|---|---|---|
| Year | |||
| Extended year | uuuu |
2024, -0001 | Recommended over yyyy |
| Calendar year | yyyy |
2024 | Use uuuu instead |
| 2-digit year | yy or uu |
24 | |
| Month | Same as LDML | ||
| Day | |||
| Day of month | d, do, dd |
1, 1st, 01 | |
| Day of year | D, Do, DD, DDD |
1, 1st, 01, 001 | |
| Week | |||
| Local week | w, wo, ww |
1, 1st, 01 | |
| ISO week | I, Io, II |
1, 1st, 01 | |
| Weekday | |||
| Short | eee, eeeee |
Mon, M | Locale day |
| Long | eeee, eeeeee |
Monday, Mo | Locale day |
| ISO | i, io, iii, iiii, iiiii, iiiiii |
1, 1st, Mon, Monday, M, Mo | |
| Hour, Minute, Second | Same as LDML | ||
| AM/PM | Same as LDML | ||
| Timezone | Extended LDML support |
Common Pattern Examples
yyyy-MM-dd→ 2024-02-08MMM d, yyyy→ Feb 8, 2024EEEE, MMMM d, yyyy→ Thursday, February 8, 2024h:mm a→ 3:45 PMHH:mm:ss→ 15:45:30
5. .NET DateTime Formats
Used by: C#, F#, VB.NET, .NET platform
Key Characteristics
- Single character codes (case-sensitive)
- Can use multiple characters for wider format
- Custom format strings combine individual specifiers
- Standard format strings (single character) produce locale-specific output
Format Specifiers
| Element | Specifier | Examples | Notes |
|---|---|---|---|
| Year | |||
| 1-2 digit year | y |
8, 24 | Minimum digits |
| 2-digit year | yy |
08, 24 | 00-99 |
| 3-digit year | yyy |
008, 024 | Minimum 3 digits |
| 4-digit year | yyyy |
0008, 2024 | |
| 5-digit year | yyyyy |
00008, 02024 | |
| Month | |||
| Numeric, no zero | M |
1, 12 | 1-12 |
| Numeric, zero-padded | MM |
01, 12 | 01-12 |
| Abbreviated name | MMM |
Jan, Dec | Locale-specific |
| Full name | MMMM |
January, December | Locale-specific |
| Day of Month | |||
| Numeric, no zero | d |
1, 31 | 1-31 |
| Numeric, zero-padded | dd |
01, 31 | 01-31 |
| Weekday | |||
| Abbreviated | ddd |
Mon, Fri | Locale-specific |
| Full name | dddd |
Monday, Friday | Locale-specific |
| Hour (12-hour) | |||
| No zero (1-12) | h |
1, 12 | Requires tt or t |
| Zero-padded (01-12) | hh |
01, 12 | Requires tt or t |
| Hour (24-hour) | |||
| No zero (0-23) | H |
0, 23 | |
| Zero-padded (00-23) | HH |
00, 23 | |
| Minute | |||
| No zero | m |
0, 59 | 0-59 |
| Zero-padded | mm |
00, 59 | 00-59 |
| Second | |||
| No zero | s |
0, 59 | 0-59 |
| Zero-padded | ss |
00, 59 | 00-59 |
| Fractional Seconds | |||
| Tenths | f |
0-9 | Always shown |
| Hundredths | ff |
00-99 | Always shown |
| Milliseconds | fff |
000-999 | Always shown |
| Optional tenths | F |
0-9 or nothing | Not shown if zero |
| Optional hundredths | FF |
00-99 or nothing | Not shown if zero |
| Optional milliseconds | FFF |
000-999 or nothing | Not shown if zero |
| Up to 7 digits | fffffff, FFFFFFF |
Nanosecond precision | |
| AM/PM | |||
| First char | t |
A, P | Locale-specific |
| Full designator | tt |
AM, PM | Locale-specific |
| Timezone | |||
| Hours offset | z |
-8, +5 | No leading zero |
| Hours offset padded | zz |
-08, +05 | With leading zero |
| Full offset | zzz |
-08:00, +05:30 | Hours and minutes |
| Other | |||
| Era | g or gg |
A.D. | Period/era |
| Time separator | : |
: | Locale-specific |
| Date separator | / |
/ | Locale-specific |
Standard Format Strings
d- Short date pattern (MM/dd/yyyy)D- Long date pattern (dddd, MMMM dd, yyyy)t- Short time pattern (h:mm tt)T- Long time pattern (h:mm:ss tt)f- Full date/time short (dddd, MMMM dd, yyyy h:mm tt)F- Full date/time long (dddd, MMMM dd, yyyy h:mm:ss tt)g- General short (M/d/yyyy h:mm tt)G- General long (M/d/yyyy h:mm:ss tt)o- ISO 8601 (yyyy-MM-ddTHH:mm:ss.fffffffK)s- Sortable (yyyy-MM-ddTHH:mm:ss)
Common Pattern Examples
yyyy-MM-dd→ 2024-02-08MMM d, yyyy→ Feb 8, 2024dddd, MMMM d, yyyy→ Thursday, February 8, 2024h:mm tt→ 3:45 PMHH:mm:ss→ 15:45:30yyyy-MM-ddTHH:mm:ss→ 2024-02-08T15:45:30
6. ISO 8601 Standard
International Standard for date and time representation
Key Characteristics
- Designed for unambiguous machine-readable formats
- Always uses Gregorian calendar
- Year-month-day order (largest to smallest units)
- Uses T as date/time separator
- Uses Z to denote UTC
Standard Representations
| Format | Pattern | Example | Notes |
|---|---|---|---|
| Date | |||
| Calendar date | YYYY-MM-DD |
2024-02-08 | Extended format |
| Calendar date | YYYYMMDD |
20240208 | Basic format |
| Week date | YYYY-Www-D |
2024-W06-4 | Week 6, day 4 |
| Week date | YYYYWwwD |
2024W064 | Basic format |
| Ordinal date | YYYY-DDD |
2024-039 | Day 39 of year |
| Ordinal date | YYYYDDD |
2024039 | Basic format |
| Year and month | YYYY-MM |
2024-02 | |
| Year only | YYYY |
2024 | |
| Time | |||
| Hours and minutes | hh:mm |
15:45 | Extended format |
| Hours and minutes | hhmm |
1545 | Basic format |
| Hours, min, sec | hh:mm:ss |
15:45:30 | Extended format |
| Hours, min, sec | hhmmss |
154530 | Basic format |
| With fractional sec | hh:mm:ss.sss |
15:45:30.123 | Variable precision |
| DateTime | |||
| Combined | YYYY-MM-DDThh:mm:ss |
2024-02-08T15:45:30 | T separator |
| Combined basic | YYYYMMDDThhmmss |
20240208T154530 | No separators |
| Timezone | |||
| UTC indicator | Z |
2024-02-08T15:45:30Z | Zulu time |
| Offset | ±hh:mm |
2024-02-08T15:45:30-08:00 | Extended format |
| Offset | ±hhmm |
2024-02-08T15:45:30-0800 | Basic format |
| Offset | ±hh |
2024-02-08T15:45:30-08 | Hours only |
Common ISO 8601 Examples
2024-02-08(Date only)15:45:30(Time only)2024-02-08T15:45:30(Local datetime)2024-02-08T15:45:30Z(UTC datetime)2024-02-08T15:45:30-08:00(With timezone offset)2024-W06-4(Week date: year 2024, week 6, Thursday)
Cross-System Comparison Table
Year Formats
| Format | LDML | strftime | Moment | date-fns | .NET | ISO 8601 |
|---|---|---|---|---|---|---|
| 4-digit | yyyy |
%Y |
YYYY |
yyyy |
yyyy |
YYYY |
| 2-digit | yy |
%y |
YY |
yy |
yy |
YY |
Month Formats
| Format | LDML | strftime | Moment | date-fns | .NET | ISO 8601 |
|---|---|---|---|---|---|---|
| Numeric no zero | M |
- | M |
M |
M |
- |
| Numeric zero-pad | MM |
%m |
MM |
MM |
MM |
MM |
| Abbreviated name | MMM |
%b |
MMM |
MMM |
MMM |
- |
| Full name | MMMM |
%B |
MMMM |
MMMM |
MMMM |
- |
Day Formats
| Format | LDML | strftime | Moment | date-fns | .NET | ISO 8601 |
|---|---|---|---|---|---|---|
| Numeric no zero | d |
- | D |
d |
d |
- |
| Numeric zero-pad | dd |
%d |
DD |
dd |
dd |
DD |
| Abbreviated weekday | EEE |
%a |
ddd |
eee |
ddd |
- |
| Full weekday | EEEE |
%A |
dddd |
eeee |
dddd |
- |
Hour Formats (12-hour)
| Format | LDML | strftime | Moment | date-fns | .NET | ISO 8601 |
|---|---|---|---|---|---|---|
| No zero (1-12) | h |
- | h |
h |
h |
- |
| Zero-pad (01-12) | hh |
%I |
hh |
hh |
hh |
- |
Hour Formats (24-hour)
| Format | LDML | strftime | Moment | date-fns | .NET | ISO 8601 |
|---|---|---|---|---|---|---|
| No zero (0-23) | H |
- | H |
H |
H |
- |
| Zero-pad (00-23) | HH |
%H |
HH |
HH |
HH |
hh |
Minute/Second Formats
| Format | LDML | strftime | Moment | date-fns | .NET | ISO 8601 |
|---|---|---|---|---|---|---|
| Minutes no zero | m |
- | m |
m |
m |
- |
| Minutes zero-pad | mm |
%M |
mm |
mm |
mm |
mm |
| Seconds no zero | s |
- | s |
s |
s |
- |
| Seconds zero-pad | ss |
%S |
ss |
ss |
ss |
ss |
AM/PM Indicators
| Format | LDML | strftime | Moment | date-fns | .NET | ISO 8601 |
|---|---|---|---|---|---|---|
| Uppercase | a |
%p |
A |
a |
tt |
N/A |
| Lowercase | aaaaa |
%P* |
a |
aaa |
- | N/A |
| First char only | - | - | - | - | t |
N/A |
*GNU extension, not POSIX standard
Timezone Formats
| Format | LDML | strftime | Moment | date-fns | .NET | ISO 8601 |
|---|---|---|---|---|---|---|
| Offset with colon | ZZZZZ or XXXXX |
- | Z |
XXX |
zzz |
±hh:mm |
| Offset no colon | ZZZ or XX |
%z |
ZZ |
XX |
- | ±hhmm |
| UTC indicator | - | - | - | X |
- | Z |
| Named timezone | z, zzzz |
%Z |
- | - | - | N/A |
Recommendations for Human-Readable Format
Based on this research, here are recommendations for a widely-recognized human-readable format:
Most Universal Patterns
-
Date Only - ISO 8601 style (MOST UNIVERSAL)
- Pattern:
YYYY-MM-DD - Example:
2024-02-08 - Recognized by: ALL systems
- Pros: Unambiguous, sortable, internationally recognized
- Cons: Less readable for some English speakers
- Pattern:
-
Date Only - Text month
- Pattern:
MMM DD, YYYYorDD MMM YYYY - Example:
Feb 08, 2024or08 Feb 2024 - Recognized by: All major systems (with slight variations)
- Pros: Very readable, avoids MM/DD vs DD/MM confusion
- Cons: Not sortable, locale-dependent
- Pattern:
-
Time Only - 24-hour (MOST UNIVERSAL)
- Pattern:
HH:mm:ss - Example:
15:45:30 - Recognized by: ALL systems
- Pros: Unambiguous, no AM/PM needed
- Cons: Some users prefer 12-hour format
- Pattern:
-
Time Only - 12-hour
- Pattern:
hh:mm:ss AMorh:mm:ss a - Example:
03:45:30 PM - Recognized by: All major systems (with variations)
- Pros: Familiar to many users
- Cons: Requires AM/PM designator
- Pattern:
-
Full DateTime - ISO 8601 (MOST UNIVERSAL)
- Pattern:
YYYY-MM-DDTHH:mm:ss - Example:
2024-02-08T15:45:30 - Recognized by: ALL systems
- Pros: Unambiguous, sortable, international standard
- Cons: T separator less readable
- Pattern:
-
Full DateTime - Human-readable
- Pattern:
MMMM DD, YYYY HH:mm:ssorDD MMMM YYYY HH:mm:ss - Example:
February 08, 2024 15:45:30 - Recognized by: All major systems (with slight variations)
- Pros: Very readable
- Cons: Verbose, locale-dependent month names
- Pattern:
Token Compatibility Summary
Highest Compatibility (work in 5-6 systems):
yyyy/YYYY- 4-digit yearMM- 2-digit month (zero-padded)dd/DD- 2-digit day (zero-padded)HH- 24-hour time (zero-padded)mm- minutes (zero-padded)ss- seconds (zero-padded)
High Compatibility (work in 4-5 systems):
MMM- Abbreviated month nameMMMM- Full month namehh- 12-hour time (zero-padded)a/A/tt- AM/PM (varies by system)
Moderate Compatibility:
EEE/ddd- Abbreviated weekdayEEEE/dddd- Full weekday- Single-letter tokens (no zero padding) - variable support
Recommended Format for timefmt Project
For maximum compatibility and readability, consider:
- For machine-readable output:
YYYY-MM-DD HH:mm:ss(ISO 8601 without T) - For human-readable output:
MMM DD, YYYY HH:mm:ss(e.g., "Feb 08, 2024 15:45:30") - For compact output:
YYYY-MM-DD HH:mm(omit seconds if not needed)
These formats:
- Avoid MM/DD vs DD/MM confusion
- Don't require AM/PM logic
- Use widely recognized token patterns
- Are unambiguous across cultures
- Balance readability with precision