Search code examples
javascriptmoment-timezone

Get the time that has been passed, taking into account the user's TimeZone with Moment


I'm doing a web application in React Native to show a list of events. These events comes from a backend configured as GMT -4 and located in America/Santo_Domingo, as TimeZone.

The date of an event that I receive from the backend is 2020-11-05T16:02:13.1018115.

My screen of events is like this:

Title: Hi, a party has started!
Description: 1 hour ago // <= could be year, month, day, hour, minute or second

Problem: Some devices reports different dates when I do new Date() to do the calculation. Those dates have hours of difference. For example, a device using the timezone America/La_Paz or Etc/GMT+12.

My conclusion was that I need to take into account the device's timezone to do my calculations. I was following this guide and I have installed Moment Timezone.

I pass the date received from the backend to this function:

 export const timeSince = (backEndTimeStamp) => {

   // get device timezone eg. -> "America/La_Paz"
   const deviceTimeZone = 'America/La_Paz';

   // Make moment of right now, using the device timezone
   const today = moment().tz(deviceTimeZone);

   // Get the UTC offset in hours
   const currentTimeZoneOffsetInHours = today.utcOffset() / 60;

   const convertedToLocalTime = formatTimeByOffset(backEndTimeStamp, currentTimeZoneOffsetInHours);

   const years = today.diff(convertedToLocalTime, 'years');
   const months = today.diff(convertedToLocalTime, 'months');
   const days = today.diff(convertedToLocalTime, 'days');
   const hours = today.diff(convertedToLocalTime, 'hours');
   const minutes = today.diff(convertedToLocalTime, 'minutes');
   const seconds = today.diff(convertedToLocalTime, 'seconds');

   let timeDiff = '';
   if (years > 0) {
     timeDiff = years + (years === 1 ? ' year' : ' years');
   } else if (months > 0) {
     timeDiff = months + (months === 1 ? ' month' : ' months');
   } else if (days > 0) {
     timeDiff = days + (days === 1 ? ' day' : ' days');
   } else if (hours > 0) {
     timeDiff = hours + (hours === 1 ? ' hour' : ' hours');
   } else if (minutes > 0) {
     timeDiff = minutes + (minutes === 1 ? ' minute' : ' minutes');
   } else if (seconds > 0) {
     timeDiff = seconds + (seconds === 1 ? ' second' : ' seconds');
   } else {
     timeDiff = 'unknown';
   }

   return timeDiff;
  }

This function handles the conversion:

export const formatTimeByOffset = (dateString, offset) => {
  // Params:
  // How the backend sends me a timestamp
  // dateString: on the form yyyy-mm-dd hh:mm:ss
  // offset: the amount of hours to add.

  // If we pass anything falsy return empty string
  if (!dateString) return '';
  if (dateString.length === 0) return '';

  // Step 1: Parse the backend date string

  // Get Parameters needed to create a new date object
  const year = dateString.slice(0, 4);
  const month = dateString.slice(5, 7);
  const day = dateString.slice(8, 10);
  const hour = dateString.slice(11, 13);
  const minute = dateString.slice(14, 16);
  const second = dateString.slice(17, 19);

  // Step: 2 Make a JS date object with the data
  const dateObject = new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}`);

  // Step 3: Get the current hours from the object
  const currentHours = dateObject.getHours();

  // Step 4: Add the offset to the date object
  dateObject.setHours(currentHours + offset);

  // Step 5: stringify the date object, replace the T with a space and slice off the seconds.
  const newDateString = dateObject
    .toISOString()
    .replace('T', ' ')
    .slice(0, 19);

  // Step 6: Return the new formatted date string with the added offset
  return `${newDateString}`;
}

Some users sees a difference between 1-4 hours.

Example:

Today: Thu Nov 05 2020 19:0803 GMT-0400
Date from backend: 2020-11-05T16:27:40.687
Date converted to local time using the function above: 2020-11-05 12:27:40
Result: 6 hours // <= Has an extra hour

I have tried so many things and I'm kinda confused.

My goal is to get the time that has been passed, taking into account the user's timeZone. Knowing that the backend send me the dates using GMT -4.

Any help is appreciated.


Solution

  • try this

    var localTime = moment.utc("2020-11-05T16:02:13.1018115").add(4, 'hour').local().fromNow();