-
Notifications
You must be signed in to change notification settings - Fork 3
/
sofatime.js
159 lines (143 loc) · 6.42 KB
/
sofatime.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// var $j = jQuery.noConflict();
console.log("loaded sofatime.js")
dayjs.extend(window.dayjs_plugin_utc)
dayjs.extend(window.dayjs_plugin_timezone)
jQuery(document).ready(function () {
if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) {
console.log("sofatime: timezone conversion not available in this environment");
return false;
}
sofatimeInitializeStrings();
jQuery('.sofatimezone-select').on('change', function() {
s24h = jQuery( this ).closest('.sofatime').find('input[type="checkbox"]:first').prop( "checked" );
sofatimeChangeAll( this.value, s24h );
});
jQuery('.sofatime-24h-checkbox').on('change', function() {
var tzValue = jQuery( this ).closest('.sofatime').find(".sofatimezone-select").val();
var s24h = this.checked
setTimeout(function(){ sofatimeChangeAll( tzValue, s24h ); }, 0)
// setTimeout(function(){ sofatimeAddLocalTimeToOptionNames( s24h ) }, 10);
});
sofatimeCheckLocalTimezoneIsInList();
sofatimeChangeAll( undefined, localIs24Hour() );
// sofatimeAddLocalTimeToOptionNames();
sofatimeAddUTCOffsetToOptionNames();
});
function sofatimeCheckLocalTimezoneIsInList() {
// list is incomplete. If user's local timezone is not in the list, add it.
var options = jQuery.map( jQuery('.sofatimezone-select:first option'), function(option) {
return option.value
});
var tz = dayjs.tz.guess();
if( !options.includes( tz ) ) {
jQuery('.sofatimezone-select').each(function( index ) {
jQuery( this ).prepend(`<option value="${tz}">${tz}</option>`);
});
}
}
function sofatimeAddLocalTimeToOptionNames(s24h = false) {
format = ( s24h ) ? "HH:mm" : "h:mma";
jQuery( ".sofatime" ).each(function( index ) {
if(jQuery( this ).data('datetime')) {
var thisDayjs = dayjs( jQuery( this ).data('datetime') );
jQuery( this ).find('option').each(function( index, option ) {
var optionName = jQuery( this ).html().replace(/^\d*:\d\da?p?m? /, "")
var localTimeString = thisDayjs.tz( option.value ).format( format )
jQuery( this ).html( localTimeString + " " + optionName)
})
}
});
}
function sofatimeAddUTCOffsetToOptionNames() {
jQuery( ".sofatime" ).each(function( index ) {
if(jQuery( this ).data('datetime')) {
var thisDayjs = dayjs( jQuery( this ).data('datetime') );
jQuery( this ).find('option').each(function( index, option ) {
var optionName = jQuery( this ).html()
var localTimeString = thisDayjs.tz( option.value ).format( "Z" )
// jQuery( this ).html( "UTC" + localTimeString + " " + optionName)
jQuery( this ).append( " (UTC" + localTimeString + ")")
})
}
});
}
function sofatimeInitializeStrings() {
var altTZnames = {
eastern: "America/New_York",
central: "America/Chicago",
mountain: "America/Denver",
pacific: "America/Los_Angeles"
}
jQuery( ".sofatime" ).each(function( index ) {
var inputText = jQuery( this ).find("span:first").text();
var dateMatches = inputText.match(/\d{4}-\d{2}-\d{2}(T| )\d{2}:\d{2}/g);
if ( dateMatches && dateMatches.length == 1 && dayjs(dateMatches[0]).isValid() ) {
var timezone = inputText.replace(dateMatches[0],"").trim();
if( timezone.match(/^z(ulu)?$/i) ) timezone = "Etc/UTC";
else timezone = timezone.replace(/^z/i,"").trim();
timezone = altTZnames[timezone.toLowerCase()] || timezone
if( isValidTimeZone( timezone ) ){
var sourceDateTime = dayjs.tz( dateMatches[0], timezone );
jQuery( this ).data('datetime', sourceDateTime.toISOString() );
}
}
if( jQuery( this ).data('datetime') ) {
jQuery( this ).find("*").show();
}
else {
jQuery( this ).addClass("sofatime-error");
jQuery( this ).find("span").prepend("[sofatime]");
jQuery( this ).find("span").append("[/sofatime]<br />Invalid input. Use a ISO 8601 date and time, followed by a valid timezone name. <br />example: 2020-01-01 15:00 America/New_York<br />Valid timezone names include \"UTC\", a name from the <a href=\"https://en.wikipedia.org/wiki/List_of_tz_database_time_zones\">Timezone Database</a>, or one of the following: Eastern, Central, Mountain, Pacific");
}
});
}
function sofatimeChangeAll(tz = dayjs.tz.guess(), s24h = false ) {
format = ( s24h ) ? "YYYY-MM-DD HH:mm" : "YYYY-MM-DD h:mma";
jQuery( ".sofatime" ).each(function( index ) {
if(jQuery( this ).data('datetime')) {
var datetimeSpan = jQuery( this ).find("span")
var thisDateFormatted = dayjs( jQuery( this ).data('datetime') ).tz(tz)
datetimeSpan.text( thisDateFormatted.format(format) );
jQuery( this ).find(".sofatimezone-select").val( tz );
jQuery( this ).find('input[type="checkbox"]').prop('checked', s24h);
}
});
}
function isValidTimeZone(tz) {
if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) {
throw 'Time zones are not available in this environment';
}
try {
Intl.DateTimeFormat(undefined, {timeZone: tz});
return true;
}
catch (ex) {
return false;
}
}
// https://stackoverflow.com/questions/27647918/detect-with-javascript-if-users-machine-is-using-12-hour-clock-am-pm-or-24-cl
function localIs24Hour(locale = navigator.language) {
return !new Intl.DateTimeFormat(locale, { hour: 'numeric' }).format(0).match(/\s/);
}
// adapted from solution by mrnateriver
// https://stackoverflow.com/questions/9772955/how-can-i-get-the-timezone-name-in-javascript
// not used because it returns "daylight / standard / summer" etc. for today's date, but may not
// apply to the date in question.
// function getTimezoneName() {
// var sourceDate = new Date();
// const short = sourceDate.toLocaleDateString(undefined);
// console.log(short)
// const full = sourceDate.toLocaleDateString(undefined, { timeZoneName: 'long' });
// console.log(full)
// // Trying to remove date from the string in a locale-agnostic way
// const shortIndex = full.indexOf(short);
// if (shortIndex >= 0) {
// const trimmed = full.substring(0, shortIndex) + full.substring(shortIndex + short.length);
// // by this time `trimmed` should be the timezone's name with some punctuation -
// // trim it from both sides
// return trimmed.replace(/^[\s,.\-:;]+|[\s,.\-:;]+$/g, '');
// } else {
// // in some magic case when short representation of date is not present in the long one, just return the long one as a fallback, since it should contain the timezone's name
// return full;
// }
// }