Time is just an illusion. —— Albert Einstein
Recently, I was developing a front-end project that needed to improve the internationalization plan, and encountered some problems when dealing with time internationalization. So I spent some time researching and got this article. However, because of the Internet on JavaScript in Date
pit article object has a grasp of a lot of, Therefore, this article is not JavaScript Date object using a guide, but only focus on front-end time international .
Speaking from the time zone
To deal with time, UTC is an inescapable name. Coordinated Universal Time (Coordinated Universal Time) is the current universal universal time standard. Timekeeping is based on an atomic clock, but it is not equal to TAI (International Atomic Time). TAI does not calculate leap seconds, but UTC will insert leap seconds from time to time, so the difference between UTC and TAI is expanding. UTC is also close to GMT (Greenwich Mean Time), but not exactly the same. Many people may have discovered that GMT has appeared less and less in recent years. This is because GMT timing is based on the earth's rotation. Due to the irregularity of the earth's rotation and gradually slowing down, it has been basically replaced by UTC.
The Date
implementation of JavaScript does not handle leap seconds. In fact, due to the increased unpredictability of leap seconds, Unix/POSIX timestamps do not consider leap seconds at all. When a leap second occurs, the Unix timestamp will repeat for one second. This also means that it is possible that one timestamp corresponds to two points in time.
Since UTC is a standard, we sometimes use UTC+/-N to express a time zone. This is easy to understand, but it is not accurate. China prevailing Asia/Shanghai
time zone most case can UTC + 8 said, but the British prevailing Europe/London
time zone UTC + N does not use a representation of the way - due to the daylight saving time system, Europe/London
in the summer is equal to UTC + 1, in Winter is equal to UTC/GMT.
The offset of a time zone from UTC is not necessarily a whole hour. For example,Asia/Yangon
currently UTC+6:30, andAustralia/Eucla
currently has a wonderful UTC+8:45 offset.
The existence of daylight saving time indicates that is not a continuous , and the time difference between time zones is not fixed. We cannot use a fixed time difference to deal with time, which is easy to realize. But one thing that is not easy to realize is that the time zone also contains its historical change information. China currently does not implement the daylight saving time system, so can we rest assured that UTC+8 is used to express China's time zone? You may have noticed that Asia/Shanghai
time zone in the previous paragraph, I used most of the term Asia/Shanghai
time zone has historically implemented daylight saving time, so Asia/Shanghai
can be represented by UTC+9 in some time periods.
new Date('1988-04-18 00:00:00')
// Mon Apr 18 1988 00:00:00 GMT+0900 (中国夏令时间)
Daylight saving time is chaotic enough, but it’s actually more chaotic than you think-some Muslim countries switch to daylight saving time four times a year (daylight saving time will be temporarily cancelled when entering Ramadan), and some countries use chaotic 15/ 30 minutes of daylight saving time instead of the usual one hour.
Don't always judge the beginning of the day
00:00
Some countries use 0:00-1:00 to switch daylight saving time, which means that the next minute at 23:59 may be 1:00.
In fact, although there are only 24 hours a day, there are more than 300 time zones currently in use (2021.10). Each time zone contains its specific history. Although some time zones seem to be consistent now, they all contain different histories. Time zones will also create new history. Due to political, economic or other reasons, some time zones will adjust their deviation from UTC (Samoa once switched from UTC-10 to UTC+14, which caused the country to disappear all day on December 30, 2011), or enable/cancel daylight saving At times, it may even cause one time zone to be re-divided into two. Therefore, in order to correctly handle each time zone, we need a database to store time zone change information. Fortunately, someone has already done this for us. Most * nix system and a large number of open source projects are using the IANA time zone database maintained by (the IANA TZ Database), which contains information about changes since the Unix timestamp 0 each time zone. Of course, this database also contains a large amount of time zone change information before the Unix timestamp 0, but the accuracy of this information is not guaranteed. The IANA time zone database is regularly updated to reflect new time zone changes and historical changes in time zones caused by newly discovered historical facts.
Windows does not use the IANA time zone database. Microsoft Windows maintains its own set of time zone database , which sometimes result in a legal system time is not lawful on another system.
Since we cannot use UTC offset to represent a time zone, we can only define a standard name for each time zone. Normally, we use <Continent>/<City> to name a time zone. The cities here are generally the most populous cities in the time zone. Therefore, we can express the prevailing time zone in China as
Asia/Shanghai
. There are also some time zones with their own aliases, such as Pacific Standard Time PST
and Coordinated Universal Time UTC
.
Time zone names use cities instead of countries because the country usually changes much faster than the city.
city is not the smallest unit of the time zone . There are many cities in multiple time zones at the same time, and even Australia has an airport . The two ends of the runway are in different time zones.
Difficulties in handling time zones
One day a few months ago, Milky Bing sent a message like this on his Telegram channel:
You are right, this problem is caused by the difference between the time zone and UTC offset. Asia/Shanghai
time zone has implemented daylight saving time around 1940 and 1986, and the switch of daylight saving time will cause the appearance and disappearance of one hour . Specifically, one hour will disappear on the day when daylight saving time is activated. For example, when daylight saving time is activated in the United Kingdom on March 28, 2020, 1:00 will jump directly to 3:00, causing 2021-03-28 01:30:00
to be illegal in the Europe/London
time zone; on the day daylight saving time is cancelled, it will There is a one-hour repetition. For example, when the UK cancels daylight saving time Europe/London
2021-10-31 01:30:00
to correspond to two time points in the 06171484296158 time zone. In the case of milk ice, 1988-04-10 00:46:50
happened to be in the hour that disappeared due to the activation of daylight saving time, so the system would consider this time string illegal and refuse to parse it.
You may notice that in the history of April Asia/Shanghai
, 1988, the 061714842961b3 time zone actually removed the hour 1:00-2:00 instead of 0:00-1:00. The deeper reason for the above problem is that in IANA TZDB 2018a and earlier versions, IANA set the wrong daylight saving time rule due to the lack of historical data, and the rule set the daylight saving time boundary between 0:00-1:00. The above problem occurs. Then the community discovered more accurate historical facts , so IANA updated the database. The above problem was resolved after updating the system's time zone database.
Let's consider another situation. A Brazilian user of your application saved a future time 2022-01-15 12:00
in 2018 (according to the law at the time, it should be a daylight saving time). Unfortunately, at that time, your application saved the time in the form of a formatted time string. Later, you find that Brazil has announced the complete abolition of the daylight saving time system in April 2019. Then 2022-01-15 12:00
has changed and becomes no longer accurate. To handle this string correctly, you need to refer to this string. The generated time (or the UTC offset calculated at the time of generation) will be processed differently. Therefore, applications should avoid using strings to transmit and store time from the beginning, but use the Unix timestamp . If you have to use a string to store time, please as much as possible:
- Use UTC to describe the time, you never know what will happen in the local time zone in the future
- If you need to describe the time in local time, you must bring the current UTC offset
The problems caused by time zone history are often unexpected and far more than imagined. In fact, the historical data of time zone is very detailed, numerous and inconsistent across devices, and there is no simple and unified processing method. When the time zone needs to be handled rigorously, it may be necessary to embed a unified time zone database at each end in the application, but such a solution on the front end will bring many problems:
- The volume is too large. Moment.js once designed a concise TZDB representation , but even though the entire file has been compressed as much as possible, it still reaches 180+KB. This is unacceptable in performance-first web applications
- Need to be updated continuously. The time zone data is always changing, and the time zone data in the app needs to be updated as soon as possible when the time zone data is updated, which brings additional maintenance costs
ES6 brings us the Intl
namespace . Here, the JavaScript runtime provides a lot of time-related internationalization capabilities. Therefore, it is possible to handle the time zone accurately without using additional data, but it is not perfect:
- The ends are not uniform. The time zone data provided by the browser may be changed by the browser version, system version, etc. The latest time zone update may not be quickly reflected on all devices
- Implementation is complicated.
JavaScript
inDate
poorly designed objects lead to achieve the perfect time zone is not easy to deal with, andIntl
object is instantiated in a namespace performance overhead is larger, the need for additional optimization
Intl
namespace, which is worth opening another article to talk about.
In real development, this requires a trade-off. At present, mainstream JavaScript time processing libraries have turned to browser built-in methods, and Polyfill is used to ensure cross-terminal consistency when needed. In this article, we will try to implement basic time internationalization without using third-party libraries. In addition, there are some details that require attention, such as the need to use Unix timestamps to correctly exchange time on each side.
Time zone conversion
The Date
JavaScript does not contain time zone information—in fact, the Date
object must represent the current time zone. By trying:
new Date('1970-01-01T00:00:00Z')
// Thu Jan 01 1970 08:00:00 GMT+0800 (中国标准时间)
You can know that the JavaScript runtime actually knows the current time zone and will convert the time in other time zones to the time in the current time zone when needed. So, how to convert local time to time in other time zones? From Date
, this does not work, because we cannot set a time zone for Date
But we can "opportunistic": the Date
time the object of plus / minus corresponding to the time difference, although Date
object still consider themselves in the local time zone, but it can not display correctly Well! But we will encounter the problem mentioned above: the time difference between time zones is not fixed, and it is difficult to calculate correctly without additional data.
Fortunately, ES6 extends the Date.prototype.toLocaleString()
Intl
namespace, so that it can accept time zone parameters and format the time according to the specified time zone. If you search for how to use JavaScript to convert time zones in search engines, you will most likely find an answer like this on StackOverflow:
const convertTimeZone = (date, timeZone) => {
return new Date(date.toLocaleString('en-US', { timeZone }))
}
const now = new Date() // Wed Oct 13 2021 01:00:00 GMT+0800 (中国标准时间)
convertTimeZone(now, 'Europe/London') // Tue Oct 12 2021 18:00:00 GMT+0800 (中国标准时间)
It is easy to understand that we use the en-US
to require that the JavaScript runtime format the time in the time zone we specify, and then reparse the time string into a time object. Here timeZone
is the name of the IANA TZDB time zone Asia/Shanghai
This string really needs to be provided by ourselves, but this is the only data we need to prepare ourselves! As long as the time zone name is provided, the browser will automatically calculate the correct time, without us having to calculate it ourselves.
For the time zone name, you can consider using @vvo/tzdb . This is a JSON export of IANA TZDB that claims to be automatically updated and has been used by several large projects. You can export all time zone names from this package.
This method looks pretty good, right? But in fact, it has two problems:
toLocaleString()
with the locale and time zoneIntl.DateTimeFormat
object in the JavaScript runtime every time it is called (detailed later), and the latter will incur expensive performance overhead (in Node 14, instantiation once Will increase the memory usage in V8 by about 46.3Kb. But this is in line with expectations, see V8 Issue . Therefore, in the case of intensive calls, you need to consider the calculation and cache the time difference, and update it after a certain period of time or when needed- The default time format formatted with
toLocaleString()
and formatted with theen-US
10/13/2021, 1:00:00 AM
. This can be correctly parsed by most browsers. but this is not standardized. Different browsers may produce different results . You can also configure the format yourself (same asIntl.DateTimeFormat
below), but still unable to construct a standardized string
Therefore, a better solution is that we need to create a reusable formatter to avoid Intl.DateTimeFormat
, and we need to manually construct a time string that conforms to the specification and reparse it into a Date
object .
const timeZoneConverter = (timeZone) => {
// 新建 DateTimeFormat 对象以供对同一目标时区重用
// 由于时区属性必须在创建 DateTimeFormat 对象时指定,我们只能为同一时区重用格式化器
const formatter = new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
timeZone
})
return {
// 提供 conver 方法以将提供的 Date 对象转换为指定时区
convert (date) {
// zh-CN 的区域设置会返回类似 1970/01/01 00:00:00 的字符串
// 替换字符即可构造出类似 1970-01-01T00:00:00 的 ISO 8601 标准格式时间字符串并被正确解析
return new Date(formatter.format(date).replace(/\//g, '-').replace(' ', 'T').trim())
}
}
}
const toLondonTime = timeZoneConverter('Europe/London') // 对于同一时区,此对象可重用
const now = new Date() // Wed Oct 13 2021 01:00:00 GMT+0800 (中国标准时间)
toLondonTime.convert(now) // Tue Oct 12 2021 18:00:00 GMT+0800 (中国标准时间)
The currentzh-CN
will generate a format string1970/01/01 00:00:00
This format is consistent across the end, but the specification does not specify the time format, This format may change in the future . A better solution is to use theformatToParts()
method (detailed later) to obtain the parts of the time string and manually splice the string in a standard format, but in this example,replace
directly has better performance.
Now, trying to repeatedly switch the time to the same time zone 1000 times, the time taken has toLocaleString()
reduced from 06171484296920 1.5 seconds to 0.04 seconds. Although the code is a bit longer, this rewrite has brought us more than 20 times performance improvement in the best case.
It should be noted that although this seems to be the final solution, this solution is still not perfect. There are mainly the following two problems:
- When intensive conversion to a different time zone is required, the performance is still poor and difficult to further optimize due to the inability to reuse the formatter
- Since
Intl.DateTimeFormat
does not support formatting milliseconds, milliseconds will be lost in the process of formatting the string. As a result, the final result may differ from the expected result by up to 999ms, which requires additional processing. For example, when we need to calculate the time difference, we may need to write:
const calcTimeDiff = (date, converter) => {
const secDate = date - date.getMilliseconds() // 去掉毫秒,避免转换前后精度差异
return converter.convert(new Date(secDate), tzName) - secDate
}
calcTimeDiff(new Date(), timeZoneConverter('Europe/London')) // -25200000
In any case, after some tossing, we still converted the time zone correctly. Are you ready to format the time string next? But before that, we have to talk about language, text and region first.
The language area is silly and confused
How to express Chinese in the computer?
zh
," you might say, "use 061714842969da."
What about simplified Chinese?
" zh-CN
." You might say the answer.
How to distinguish the simplified Chinese used in Singapore and the simplified Chinese used in mainland China?
Hmm... good question.
To be able to distinguish different simplified Chinese correctly, we have to return to the definition first. In fact, "internationalization" is not just language translation. Internationalization includes a set of localization solutions area To accurately represent an internationalization scheme, we actually need to determine at least three attributes: language (Language), text (Script) and region (Locale).
- language usually refers to voice language. Different languages have their own pronunciation rules, which are difficult to communicate. Such as Chinese and English are both languages
- text corresponds to the writing method of a certain language, and there may be multiple writing schemes for the same language. For example, Chinese mainly has two writing schemes: simplified and traditional
- area refers to the region for internationalization. The same language and script may have different usage habits in different regions. For example, Singapore and Mainland China both use simplified Chinese, but there are some differences in the wording habits of the two places.
Only by determining these three attributes, we can correctly define an internationalization program (or regional settings ). Of course, there are many other attributes that can more accurately express a certain locale, but usually language, text, and region are enough.
Therefore, based on BCP 47 , we can know:
cmn-Hans-CN = 中文普通话-简体-中国大陆
cmn-Hans-SG = 中文普通话-简体-新加坡
cmn-Hant-TW = 中文普通话-繁体-台湾
yue-Hant-HK = 中文粤语-繁体-香港
Wait, what's all this? And what is BCP 47? BCP is a "best current practice" document published by the IETF, and BCP 47 is a collection of some internationalization-related ISO and memos, and it is also the current standard for expressing locales used by HTML and ECMAScript. The locale label defined by BCP 47 is actually more complicated, but for most simple use cases, the format in the above example is completely sufficient. To put it simply, wants to express a regional setting, we will use language [-text][-region] format, and the text and region are optional . For the specific codes of each part, BCP 47 also has specific definitions. in:
- The language uses the two-letter code defined by ISO 639-1 (for
zh
en
for Chinese and 06171484296bf4 for English) or the three-letter code defined by ISO 639-2/3cmn
eng
for Mandarin Chinese and 06171484296bf8 for English). lower case - The text uses ISO 15924 , and usually the first letter is capitalized. For example, Simplified Chinese is
Hans
and Traditional Chinese isHant
- Regional commonly used ISO 3166-1 defined two-letter code, usually capitalized, such as mainland China as
CN
, UKGB
The relationship between ISO 639-1/2/3 is actually: ISO 639-1 is the earliest specification that uses two letters to represent languages, but the number of languages cannot be represented by only two codes. Therefore, ISO 639-2 and 3 were later revised to use three letters to indicate more languages. Usually the 639-1 code and the ISO-2/3 code have a one-to-many relationship. For example, Chinesezh
is actually the macrolanguage ofcmn
wuu
zh
as the macro language, 06171484296cd8 (Chinese Wu),hak
(Chinese Hakka),yue
(Chinese Cantonese). From the specification, we should now use the ISO 639-2/3 code instead of the ISO 639-1 code , but due to historical resistance and real needs, the classification does not need to be so detailed, etc., uses ISO 639-1 to specify the language is still very Common and fully acceptable . In addition, in particular, we define the unspecified language in ISO 639-3 asund
.
Therefore, for the two questions at the beginning of this section, the correct answers in BCP 47 are actually:
zh = 中文
cmn = 中文普通话
zh-Hans = 中文-简体
cmn-Hans = 中文普通话-简体
zh-CN
actually refers to the Chinese used in mainland China, and of course it also includes the traditional Chinese used in mainland China. However, because in most cases only one type of text is used in a region, in many cases we can ignore the word , that is, use zh-CN
(or cmn-CN
) to represent the simplified Chinese Mandarin in mainland China-after all, in most cases The use of traditional and non-Mandarin Chinese in mainland China is very rare.
In fact,zh-Hans
andzh-Hant
have been marked asredundant
, so use onlyzh-CN
orcmn-Hans-CN
as much as possible. A list of all locale names can be found at IANA .
Now we can accurately define a locale. But we still have some small needs. For example, we want cmn-Hans-CN
, but obviously the representation method we defined above cannot express this requirement. Fortunately, Unicode provides the u extension for BCP 47. [option] after the locale name to express a more detailed variation. So we have:
cmn-Hans-CN-u-ca-chinese = 中文普通话-简体-中国大陆-u-日历-中国农历
jpn-Jpan-JP-u-ca-japanese = 日语-日文汉字/平假名/片假名-日本-u-日历-日本日历
cmn-Hans-CN-u-nu-hansfin = 中文普通话-简体-中国大陆-u-数字-简体大写数字
u The specific options for the extension can be found on the Unicode website . And multiple u extensions can also be connected-so we can even write the cmn-Hans-CN-u-ca-chinese-nu-hansfin
. Of course, I believe you can now understand the meaning of this regional setting.
Different regions may have different calendar usage habits. For example, China has the need to use the lunar calendar, and Thailand has the need to use the Buddhist calendar. We can specify different calendars through the u extension. However, in most cases we will use the standard ISO 8601 calendar (gregory), and the
Date
object of JavaScript only supports this kind of calendar.You can use the BCP47 language subtag lookup tool to quickly check whether the BCP 47 regional tags you write are standard.
Finally we can correctly express a regional setting that perfectly meets our needs. Next, let's start formatting the time.
Format time
I will do this!
const formatDate(date) => {
return `${date.getFullYear()}-${`${date.getMonth() + 1}`.padStart(2, '0')}-${`${date.getDate()}`.padStart(2, '0')} ${`${date.getHours()}`.padStart(2, '0')}:${`${date.getMinutes()}`.padStart(2, '0')}:${`${date.getSeconds()}`.padStart(2, '0')}`
}
formatDate(new Date()) // 2021-10-13 01:00:00
Is it over...? Regardless of whether such format codes are difficult to read, although the above date format is internationally not all regions are accustomed to this date representation method . For example, English-speaking countries/regions are accustomed to adding the week to the date in many cases, while Arabic-speaking countries/regions are accustomed to using Arabic numbers in some cases (rather than the commonly used Arabic-Indian numbers); another example is American English-speaking countries/regions customary month -Day-year date notation, while British English countries/regions are customary in day-month-year date notation...The difference in the format of time representation in different regions is huge. It is difficult for us to pass a simple Ways to format a date correctly and internationally.
Fortunately, ES6 has already paved the way for us. Intl.DateTimeFormat
mentioned above? We use it to instantiate a date formatter and use it for date internationalization.
Let's just look at the example:
const options = {
year: 'numeric',
month: 'short',
day: 'numeric',
weekday: 'long'
}
const now = new Date()
const enUSFormatter = new Intl.DateTimeFormat('en-US', options)
const zhCNFormatter = new Intl.DateTimeFormat('zh-CN', options)
const zhCNAltFormatter = new Intl.DateTimeFormat('zh-CN-u-ca-chinese', options)
const zhCNAlt2Formatter = new Intl.DateTimeFormat('zh-CN-u-ca-roc-nu-hansfin', options)
const jaFormatter = new Intl.DateTimeFormat('ja', options)
const jaAltFormatter = new Intl.DateTimeFormat('ja-JP-u-ca-japanese', options)
const arEGFormatter = new Intl.DateTimeFormat('ar-EG', options)
enUSFormatter.format(now) // Wednesday, Oct 13, 2021
zhCNFormatter.format(now) // 2021年10月13日星期三
zhCNAltFormatter.format(now) // 2021辛丑年九月8星期三
zhCNAlt2Formatter.format(now) // 民国壹佰壹拾年拾月拾叁日星期三
jaFormatter.format(now) // 2021年10月13日水曜日
jaAltFormatter.format(now) // 令和3年10月13日水曜日
arEGFormatter.format(now) // الأربعاء، ١٣ أكتوبر ٢٠٢١
Here we use ISO 639-1 codes to represent languages because of the fact that ISO 639-1 codes are more common and universal. In most
Intl.DateTimeFormat
, we can also use the ISO 639-2/3 code to represent the language (but it will actually fallback to the corresponding ISO 639-1 code).You can also replace the use of the u extension in the locale name by setting the
calendar
attribute and thenumberingSystem
options
This is also the recommended way.
This is very intuitive, we can specify the locale and formatting options to initialize a formatter, and then use the format
method of the formatter Date
object. The formatting options here are actually very flexible. Not only the date can be formatted, but the time can also be formatted flexibly. There are many combinations to choose from. We will not explain each option in detail here, you can visit MDN document to learn more.
As mentioned earlier, Intl.DateTimeFormat
cannot format milliseconds.
However, it should be noted that the JavaScript runtime does not necessarily support all locale settings, nor does it necessarily support all formatting options . When encountering unsupported situations, Intl.DateTimeFormat
will silently fallback to the most matching support item by default, so you may need to check extra when dealing with uncommon locales or options. You can use the Intl.DateTimeFormat.supportedLocalesOf()
static method to determine whether the specified locale is supported at the current runtime, or you can call the resolvedOptions()
method on the object after instantiating the formatter to check whether the runtime parsing results are consistent with expectations.
new Intl.DateTimeFormat('yue-Hant-CN').resolvedOptions()
// {locale: 'zh-CN', calendar: 'gregory', …}
// fallback 至 zh-CN,与 yue-CN 的预期不一致
In addition, as you can see, the text JavaScript runtimes used in date formatting in various languages have been built-in for us. Therefore, we can even use these internationalization features to reduce the number of strings that need to be translated for our application-the fewer translations packaged into the application, the smaller the application size-for example, to get the name corresponding to seven days a week :
const getWeekdayNames = (locale) => {
// 基于一个固定日期计算,这里选择 1970.1.1
// 不能使用 0,因为 Unix 时间戳 0 在不同时区的日期不一样
const base = new Date(1970, 0, 1).getTime()
const formatter = new Intl.DateTimeFormat(locale, { weekday: 'short' })
return Array.from({ length: 7 }, (_, day) => (
formatter.format(new Date(base + 3600000 * 24 * (-4 + day))) // 1970.1.1 是周四
))
}
getWeekdayNames('en-US') // ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
getWeekdayNames('zh-CN') // ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
getWeekdayNames('ja') // ['日', '月', '火', '水', '木', '金', '土']
getWeekdayNames('ar-EG') // ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت']
Of course, if you still don't like the format provided by the runtime, we still have the formatToParts()
method mentioned above. Let's look at a simple example:
new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'short',
day: 'numeric',
weekday: 'long',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
}).formatToParts(new Date())
// [
// { type: 'year', value: '2021' },
// { type: 'literal', value: '年' },
// { type: 'month', value: '10' },
// { type: 'literal', value: '月' },
// { type: 'day', value: '13' },
// { type: 'literal', value: '日' },
// { type: 'weekday', value: '星期三' },
// { type: 'literal', value: ' ' },
// { type: 'dayPeriod', value: '上午' },
// { type: 'hour', value: '1' },
// { type: 'literal', value: ':' },
// { type: 'minute', value: '00' },
// { type: 'literal', value: ':' },
// { type: 'second', value: '00' }
// ]
Then, you can parse this array yourself to construct the time format you want. Finally, we can also use Intl.RelativeTimeFormat
to format relative dates. Of course, we will not explain this API in detail here, you can refer to the MDN document . Let's just look at a simple example:
const getRelativeTime = (num, unit, locale) => {
return new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(num, unit)
}
getRelativeTime(-3, 'day', 'en-US') // 3 days ago
getRelativeTime(-1, 'day', 'zh-CN') // 昨天
getRelativeTime(0, 'second', 'zh-CN') // 现在
getRelativeTime(3, 'hour', 'ja') // 3 時間後
Intl.RelativeTimeFormat
is a relatively late entry into the standard, so the browser support is poor, you may need to use Polyfill . However, the latest versions of mainstream browsers (2021.10) all support this API.
future
I hope that the time zone conversion part of this article can be outdated soon-this is not nonsense. At present (2021.10) TC39's Temporal
proposal has entered Stage 3. Temporal
proposal defines a new, time zone-friendly Temporal
namespace, and expects to enter the standard soon and eventually be applied to the production environment . Temporal
defines the complete time zone, time period, and calendar rule processing, and has a simple and clear API. At that time, JavaScript's time zone processing would no longer be so painful. Since the Temporal
proposal has not yet entered the standard and the API is not stable yet, we cannot use it in a production environment, but we can look at a simple example to experience the power of this API.
const zonedDateTime = Temporal.ZonedDateTime.from({
timeZone: 'America/Los_Angeles',
year: 1995,
month: 12,
day: 7,
hour: 3,
minute: 24,
second: 30,
millisecond: 0,
microsecond: 3,
nanosecond: 500,
calendar: 'iso8601'
}) // 1995-12-07T03:24:30.0000035-08:00[America/Los_Angeles]
If you want to start using Temporal
immediately, Polyfill is now available.
However, the time zone issue will not disappear, and it will be difficult to integrate the habits of various regions. International processing time is extremely complex , the time international front-end is still worthy of our serious attention.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。