Skip to content

Commit 1a9f1a1

Browse files
committed
Add local timezone formatting demo in Alpine.js.
1 parent 90dd2ca commit 1a9f1a1

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ with.
1010

1111
## My JavaScript Demos - I Love JavaScript!
1212

13+
* [Formatting Dates In The Local Timezone With Alpine.js](https://bennadel.github.io/JavaScript-Demos/demos/local-date-formatter-alpine3)
1314
* [CSV To CTE Transformer In Angular 18](https://bennadel.github.io/JavaScript-Demos/demos/csv-to-cte-angular18/dist)
1415
* [Route Changes With OnPush Change Detection In Angular 18](https://bennadel.github.io/JavaScript-Demos/demos/on-push-route-change-angular18/dist)
1516
* [Signals And Array Mutability In Angular 18](https://bennadel.github.io/JavaScript-Demos/demos/signal-array-angular18/dist)
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<title>
5+
Formatting Dates In The Local Timezone With Alpine.js
6+
</title>
7+
<link rel="stylesheet" type="text/css" href="./main.css" />
8+
</head>
9+
<body>
10+
11+
<h1>
12+
Formatting Dates In The Local Timezone With Alpine.js
13+
</h1>
14+
15+
<!--
16+
In the following examples, let's assume that the already-rendered date string was
17+
rendered on the server using the UTC timezone.
18+
-->
19+
<p>
20+
<time
21+
x-data="LocalDateFormat"
22+
data-mask="mmmm d, yyyy 'at' HH:mmtt"
23+
datetime="2024-11-17T16:38:48Z">
24+
Nov 17, 2024 <!-- Formatted in UTC. -->
25+
</time>
26+
</p>
27+
<p>
28+
<time
29+
x-data="LocalDateFormat"
30+
data-mask="mmmm d, yyyy 'at' HH:mmtt"
31+
datetime="2024-11-20T14:40:42.832Z">
32+
Nov 20, 2024 <!-- Formatted in UTC. -->
33+
</time>
34+
</p>
35+
36+
<script type="text/javascript" src="../../vendor/alpine/3.13.5/alpine.3.13.5.min.js" defer></script>
37+
<script type="text/javascript">
38+
39+
/**
40+
* This Alpine.js component replaces the text-content of the host element with a
41+
* date-string formatted in the user's local timezone. It does this by parsing the
42+
* datetime attribute into a local Date object and then re-masking it.
43+
*
44+
* Note: This is not an Internationalization technique - it doesn't use the Intl
45+
* module, though I'm sure it could be updated to do so. This is more of a higher-
46+
* level exploration client-side date-formatting.
47+
*/
48+
function LocalDateFormat() {
49+
50+
// In a <time> element, the "datetime" attribute is intended to represent a
51+
// period in time. For the sake of this demo, I'm going to assume that the
52+
// attribute contains a full UTC date/time value.
53+
var date = new Date( this.$el.getAttribute( "datetime" ) );
54+
var mask = this.$el.dataset.mask;
55+
56+
// In order to translate the server-side date formatting into a client-side
57+
// context in the user's local timezone, this Alpine.js component expects a
58+
// date mask to be provided as a data-attribute. The text content of the host
59+
// will be replaced with the interpolation of the date parts and the mask.
60+
this.$el.textContent = mask.replace(
61+
/'([^']*)'|y+|m+|d+|H+|h+|n+|s+|T+|t+/g,
62+
( $0, $1 ) => {
63+
64+
// Return escaped string (less the surrounding quotes).
65+
if ( $1 ) {
66+
67+
return $1;
68+
69+
}
70+
71+
return translations[ $0 ]( date );
72+
73+
}
74+
75+
);
76+
77+
}
78+
79+
// Utility methods for applying mask parts to a given date.
80+
var translations = {
81+
yyyy: ( date ) => String( date.getFullYear() ),
82+
yy: ( date ) => String( date.getYear() - 100 ), // Deprecated, never use short year.
83+
mmmm: ( date ) => String( monthNames[ date.getMonth() ].long ),
84+
mmm: ( date ) => String( monthNames[ date.getMonth() ].short ),
85+
mm: ( date ) => String( date.getMonth() ).padStart( 2, "0" ),
86+
m: ( date ) => String( date.getMonth() ),
87+
dddd: ( date ) => String( dayNames[ date.getDate() ].long ),
88+
ddd: ( date ) => String( dayNames[ date.getDate() ].short ),
89+
dd: ( date ) => String( date.getDate() ).padStart( 2, "0" ),
90+
d: ( date ) => String( date.getDate() ),
91+
HH: ( date ) => String( date.getHours() ).padStart( 2, "0" ),
92+
H: ( date ) => String( date.getHours() ),
93+
hh: ( date ) => String( 12 % date.getHours() ).padStart( 2, "0" ),
94+
mm: ( date ) => String( date.getMinutes() ).padStart( 2, "0" ),
95+
m: ( date ) => String( date.getMinutes() ),
96+
ss: ( date ) => String( date.getSeconds() ).padStart( 2, "0" ),
97+
s: ( date ) => String( date.getSeconds() ),
98+
TT: ( date ) => String( date.getHours() >= 12 ? "PM" : "AM" ),
99+
tt: ( date ) => String( date.getHours() >= 12 ? "pm" : "am" )
100+
};
101+
var monthNames = [
102+
{ short: "Jan", long: "January" },
103+
{ short: "Feb", long: "February" },
104+
{ short: "Mar", long: "March" },
105+
{ short: "Apr", long: "April" },
106+
{ short: "May", long: "May" },
107+
{ short: "Jun", long: "June" },
108+
{ short: "Jul", long: "July" },
109+
{ short: "Aug", long: "August" },
110+
{ short: "Sep", long: "September" },
111+
{ short: "Oct", long: "October" },
112+
{ short: "Nov", long: "November" },
113+
{ short: "Dec", long: "December" }
114+
];
115+
var dayNames = [
116+
{ short: "Sun", long: "Sunday" },
117+
{ short: "Mon", long: "Monday" },
118+
{ short: "Tue", long: "Tuesday" },
119+
{ short: "Wed", long: "Wednesday" },
120+
{ short: "Thr", long: "Thursday" },
121+
{ short: "Fri", long: "Friday" },
122+
{ short: "Sat", long: "Saturday" }
123+
];
124+
125+
</script>
126+
127+
</body>
128+
</html>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
html {
2+
font-family: monospace ;
3+
font-size: 140% ;
4+
}

0 commit comments

Comments
 (0)