Skip to content

Instantly share code, notes, and snippets.

@meyt
Created April 3, 2022 19:36
Show Gist options
  • Save meyt/63974ce6cde38d3ad90e48573e2e80aa to your computer and use it in GitHub Desktop.
Save meyt/63974ce6cde38d3ad90e48573e2e80aa to your computer and use it in GitHub Desktop.
famous strftime (linux+python) format implementation in js (intl)
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