What, you are still using momentJs to deal with relative time

I think, the following piece of code, do you often use it in development to calculate how much time has passed since now:

import moment from 'moment' // 61k (gzipped:19.k)
function Relative(props) {
    
    
	const timeString = moment(props.date).fromNow()
	return <>
		{
    
    timeString}
	</>
}

However, you actually use a package with a size of 20k (or compressed, not compressed 61k) only for date conversion? really? What you want is just a date conversion.

Now, after all this scaring from me, you might be wondering if you could do this:

function nativeGetRelativeTime(unit = 'days', amount = 2) {
    
    
  return `in ${
      
      amount} ${
      
      unit}s`
}

No, please don't do this. Although relative time may seem like a simple problem for the time being, you should be aware that relative time has many complex problems that need to be solved, such as:

  • Abbreviations: "1 day ago" is usually not displayed? Usually words such as "yesterday", "tomorrow" or "next year" are displayed
  • Future and Past: For example, instead of displaying "within -2 days", we display "2 days ago"

There may also be other issues, such as time zone issues . Once these complex problems come, developers often use libraries like momentJsand to solve the problem. dayjsAlthough, the following piece of code can also try to solve your problem:

function nativeGetRelativeTime(locale, unit, amount) {
    
    
  if (locale === 'zh') {
    
    
    const isPlural = amount !== 1 && amount !== -1
    const isPast = amount < 0
    if (amount === 1 && unit === 'day') return '明天'
    if (amount === -1 && unit === 'day') return '昨天'
    if (amount === 1 && unit === 'year') return '明年'
    if (isPast) {
    
    
      return `${
      
      amount} ${
      
      unit}${
      
      isPlural ? 's' : ''}`
    }
    return `in ${
      
      amount} ${
      
      day}${
      
      isPlural ? 's' : ''}`
  }

}

However, please don't do it. Because it seems like it's getting complicated. And a built-in object that I recommend to you can help you solve the problem of relative time.

Intl.RelativeTimeFormat

Again, when you encounter these situations, remember that there are already many built-in solutions to common problems in modern front-ends, which can be easily used.

In the face of the relative time problem mentioned in this article, what I want to talk about is Intl.RelativeTimeFormatthis object.

I first use the following piece of code to style its convenience:

const rtf = new Intl.RelativeTimeFormat('en', {
    
    
  numeric: 'auto'
})

rtf.format(1, 'day') // 'tomorrow'
rtf.format(-2, 'year') // '2 years ago'
rtf.format(10, 'minute') // 'in 10 minutes'

Also, it handles different timezones nicely:

const rtf = new Intl.RelativeTimeFormat('es-ES', {
    
    
  numeric: 'auto'
})
rtf.format(1, 'day') // 'mañana'
rtf.format(-2, 'year') // 'hace 2 años'
rtf.format(10, 'minute') // 'dentro de 10 minutos'

You can even just pass in navigator.languageas the first argument:

const rtf = new Intl.RelativeTimeFormat(
  navigator.language // ✅
)

Among other things, Intl.RelativeTimeFormatsupported units include:"year", "quarter", "month", "week", "day", "hour", "minute", 和 "second"

Now, going back to our original example, let's Intl.RelativeTimeFormatrewrite it as:

First, let's write a simple wrapper function to handle relative time conversions:

function Relative(props) {
    
    
  const timeString = getRelativeTimeString(props.date)
  
  return <>
    {
    
    timeString}
  </>
}

Next, we use Intl.RelativeTimeFormatthe object to implement getRelativeTimeStringthe function:

export function getRelativeTimeString(
  date: Date | number,
  lang = navigator.language
): string {
    
    
  const timeMs = typeof date === "number" ? date : date.getTime();
  const deltaSeconds = Math.round((timeMs - Date.now()) / 1000);
  const cutoffs = [60, 3600, 86400, 86400 * 7, 86400 * 30, 86400 * 365, Infinity];

  const units: Intl.RelativeTimeFormatUnit[] = ["second", "minute", "hour", "day", "week", "month", "year"];

  const unitIndex = cutoffs.findIndex(cutoff => cutoff > Math.abs(deltaSeconds));
  const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
  const rtf = new Intl.RelativeTimeFormat(lang, {
    
     numeric: "auto" });
  return rtf.format(Math.floor(deltaSeconds / divisor), units[unitIndex]);
}

Using date-fns

But if you don't want your own solution, there is also an open source solution. date-fnsIs a great JavaScript date tool library, each date supports 树摇a separate export in the way.

Among them, date-fnsthere is a built-in intlFormatDistancefunction, which is Intl.RelativeTimeFormata small wrapper of , which does exactly what we need. And, its size is under 2kb.

Look at the following code, is the code much simpler:

insert image description here

Intl.DateTimeFormat

In addition to this, Intl.DateTimeformatformatting dates and times are also provided:

new Intl.DateTimeFormat('en-US').format(new Date())
// -> 1/23/2023

new Intl.DateTimeFormat('en-US', {
    
    
  dateStyle: 'full'
}).format(new Date())
// -> Monday, January 23, 2023

new Intl.DateTimeFormat('en-US', {
    
    
  timeStyle: 'medium'
}).format(new Date())
// -> 4:17:23 PM

new Intl.DateTimeFormat('en-US', {
    
    
  dayPeriod: 'short', hour: 'numeric'
}).format(new Date())
// -> 4 in the afternoon

Intl.NumberFormat

Also, Intl.NumberFormatthis object can format numbers for you:

new Intl.NumberFormat('en', {
    
     
  style: 'currency', currency: 'USD' 
}).format(123456.789)
// -> $123,456.79

new Intl.NumberFormat('de-DE', {
    
     
  style: 'currency', currency: 'EUR' 
}).format(123456.789)
// -> 123.456,79 €

new Intl.NumberFormat('pt-PT', {
    
    
  style: 'unit', unit: 'kilometer-per-hour'
}).format(50));
// -> 50 km/h

(16).toLocaleString('en-GB', {
    
    
  style: 'unit', unit: 'liter', unitDisplay: 'long',
}));
// -> 16 litres

Currently, all major browsers are supported, as well as Node.js and Deno Intl.RelativeTimeFormat.
If you are still using momentJsa large data processing library like this, consider whether Intl.RelativeTimeFormat, Intl.DateTimeFormatthese objects can help you solve the problems you face.

insert image description here
Here is the programming track, see you in the next article~

Guess you like

Origin blog.csdn.net/ImagineCode/article/details/131119562