Created
April 3, 2022 19:36
-
-
Save meyt/63974ce6cde38d3ad90e48573e2e80aa to your computer and use it in GitHub Desktop.
famous strftime (linux+python) format implementation in js (intl)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function IranLocale () { | |
const weekdays = 'یک\u200Cشنبه_دوشنبه_سه\u200Cشنبه_چهارشنبه_پنج\u200Cشنبه_جمعه_شنبه'.split('_') | |
const weekdaysAbbr = 'ی_د_س_چ_پ_ج_ش'.split('_') | |
const monthNames = ('فروردین_اردیبهشت_خرداد_تیر_مرداد_شهریور_مهر_آبان_آذر_دی_بهمن_اسفند').split('_') | |
const monthNamesAbbr = 'فرو_ارد_خرد_تیر_مرد_شهر_مهر_آبا_آذر_دی_بهم_اسف'.split('_') | |
const intlDate = new Intl.DateTimeFormat('en-US', { | |
hour12: false, | |
calendar: 'persian', | |
numberingSystem: 'arabext', | |
year: 'numeric', | |
month: 'numeric', | |
day: 'numeric', | |
hour: 'numeric', | |
minute: 'numeric' | |
}) | |
const intlNum = new Intl.NumberFormat('fa-IR', { useGrouping: false }) | |
const self = this | |
function zeroPad (nNum, nPad) { | |
return ('' + (Math.pow(10, nPad) + nNum)).slice(1) | |
} | |
this.formatToParts = function (date) { | |
const parts = {} | |
intlDate.formatToParts(date).forEach((v) => { | |
parts[v.type] = isNaN(v.value) ? v.value : parseInt(v.value) | |
}) | |
return parts | |
} | |
this.formatNumber = function (v) { | |
return intlNum.format(v) | |
} | |
this.strftime = function (date, format) { | |
// partial strftime | |
const parts = self.formatToParts() | |
const nYear = parts.year | |
const nMonth = parts.month | |
const nDate = parts.day | |
const nDay = date.getDay() | |
const isLeapYear = (nYear % 4 === 0 && nYear % 100 !== 0) || nYear % 400 === 0 | |
const aDayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] | |
const xI = (parts.hour + 11) % 12 + 1 | |
const xJ = aDayCount[nMonth] + nDate + ((nMonth > 1 && isLeapYear()) ? 1 : 0) | |
const matches = { | |
// Weekday as locale’s abbreviated name. | |
'%a': weekdaysAbbr[nDay], | |
// Weekday as locale’s full name. | |
'%A': weekdays[nDay], | |
// Weekday as a decimal number, where 0 is Sunday and 6 is Saturday. | |
'%w': '' + nDay, | |
// Day of the month as a zero-padded decimal number. | |
'%d': zeroPad(nDate, 2), | |
// Day of the month as a decimal number. (Platform specific) | |
'%-d': '' + nDate, | |
// Month as locale’s abbreviated name. | |
'%b': monthNamesAbbr[nMonth], | |
// Month as locale’s full name. | |
'%B': monthNames[nMonth], | |
// Month as a zero-padded decimal number. | |
'%m': zeroPad(nMonth, 2), | |
// Month as a decimal number. (Platform specific) | |
'%-m': '' + nMonth, | |
// Year without century as a zero-padded decimal number. | |
'%y': ('' + parts.year).slice(2), | |
// Year with century as a decimal number. | |
'%Y': parts.year, | |
// Hour (24-hour clock) as a zero-padded decimal number. | |
'%H': zeroPad(parts.hour, 2), | |
// Hour (24-hour clock) as a decimal number. (Platform specific) | |
'%-H': '' + parts.hour, | |
// Hour (12-hour clock) as a zero-padded decimal number. | |
'%I': zeroPad(xI, 2), | |
// Hour (12-hour clock) as a decimal number. (Platform specific) | |
'%-I': '' + xI, | |
// Locale’s equivalent of either AM or PM. | |
'%p': (parts.hour < 12) ? 'AM' : 'PM', | |
'%P': (parts.hour < 12) ? 'am' : 'pm', | |
// Minute as a zero-padded decimal number. | |
'%M': zeroPad(date.getMinutes(), 2), | |
// Minute as a decimal number. (Platform specific) | |
'%-M': '' + date.getMinutes(), | |
// Second as a zero-padded decimal number. | |
'%S': zeroPad(date.getSeconds(), 2), | |
// Second as a decimal number. (Platform specific) | |
'%-S': '' + date.getSeconds(), | |
// UTC offset in the form ±HHMM[SS[.ffffff]] | |
// (empty string if the object is naive). | |
'%z': date.toTimeString().replace(/.+GMT([+-]\d+).+/, '$1'), | |
// Time zone name (empty string if the object is naive). | |
'%Z': date.toTimeString().replace(/.+\((.+?)\)$/, '$1'), | |
// Day of the year as a zero-padded decimal number. | |
'%j': zeroPad(xJ, 3), | |
// Day of the year as a decimal number. (Platform specific) | |
'%-j': '' + xJ, | |
// Week number of the year (Sunday as the first day of the week) as a | |
// zero padded decimal number. All days in a new year preceding the | |
// first Sunday are considered to be in week 0. | |
'%U': zeroPad('' + (nDay || 7), 2), | |
'%u': '' + (nDay || 7), | |
// Locale’s appropriate date and time representation. | |
'%c': date.toUTCString(), | |
// Locale’s appropriate date representation. | |
'%x': date.toLocaleDateString(), | |
// Locale’s appropriate time representation. | |
'%X': date.toLocaleTimeString(), | |
// The number of seconds since the Epoch, 1970-01-01 00:00:00 | |
// +0000 (UTC). (TZ) (Calculated from mktime(tm).) | |
'%s': Math.round(date.getTime() / 1000) | |
// // The preferred date and time representation for the current | |
// // locale. (The specific format used in the current locale | |
// // can be obtained by calling nl_langinfo(3) with D_T_FMT as | |
// // an argument for the %c conversion specification, and with | |
// // ERA_D_T_FMT for the %Ec conversion specification.) (In | |
// // the POSIX locale this is equivalent to %a %b %e %H:%M:%S | |
// // %Y.) | |
// '%C': Math.floor(nYear / 100), | |
// // Microsecond as a decimal number, zero-padded on the left. | |
// '%f': '', | |
// // Week number of the year (Monday as the first day of the week) as a | |
// // decimal number. All days in a new year preceding the first Monday are | |
// // considered to be in week 0. | |
// '%W': '', | |
// // Like %d, the day of the month as a decimal number, but a | |
// // leading zero is replaced by a space. (SU) (Calculated from | |
// // tm_mday.) | |
// '%e': nDate, | |
// // Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99) | |
// '%F': date.toISOString().slice(0,10), | |
// // The ISO 8601 week-based year (see NOTES) with century as a | |
// // decimal number. The 4-digit year corresponding to the ISO | |
// // week number (see %V). This has the same format and value | |
// // as %Y, except that if the ISO week number belongs to the | |
// // previous or next year, that year is used instead. (TZ) | |
// // (Calculated from tm_year, tm_yday, and tm_wday.) | |
// '%G': getThursday().getFullYear(), | |
// // Like %G, but without century, that is, with a 2-digit year | |
// // (00–99). (TZ) (Calculated from tm_year, tm_yday, and | |
// // tm_wday.) | |
// '%g': ('' + getThursday().getFullYear()).slice(2), | |
// // The hour as a decimal number using a 12-hour clock (range | |
// // 01 to 12). (Calculated from tm_hour.) | |
// '%I': zeroPad((nHour+11)%12 + 1, 2), | |
// // The hour (24-hour clock) as a decimal number (range 0 to | |
// // 23); single digits are preceded by a blank. (See also | |
// // %H.) (Calculated from tm_hour.) (TZ) | |
// '%k': '' + nHour, | |
// // The hour (12-hour clock) as a decimal number (range 1 to | |
// // 12); single digits are preceded by a blank. (See also | |
// // %I.) (Calculated from tm_hour.) (TZ) | |
// '%l': (nHour+11)%12 + 1, | |
// // The ISO 8601 week number (see NOTES) of the current year | |
// // as a decimal number, range 01 to 53, where week 1 is the | |
// // first week that has at least 4 days in the new year. See | |
// // also %U and %W. (Calculated from tm_year, tm_yday, and | |
// // tm_wday.) (SU) | |
// '%V': (function() { | |
// var target = getThursday(), | |
// n1stThu = target.valueOf(); | |
// target.setMonth(0, 1); | |
// var nJan1 = target.getDay(); | |
// if (nJan1!==4) target.setMonth(0, 1 + ((4-nJan1)+7)%7); | |
// return zeroPad(1 + Math.ceil((n1stThu-target)/604800000), 2); | |
// })(), | |
} | |
return format.replace(/%[a-z-]/gi, v => matches[v] || v) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment