JavaScript: how to get date time at a specified timezone - javascript

Is there a way to get a time that is local to a specified timezone in JavaScript? Basically, I'm looking for a way to say, what is the ISO time string of 2pm in New York?
I have a hack to do so, where the date is a parse-able date string, and tz is a timezone identifier, such as America/New_York.
function getDateInTZ(date, tz) {
const formatter = new Intl.DateTimeFormat([], {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
fractionalSecondDigits: 3,
timeZone: tz,
});
const localDate = new Date(date);
const localDateAtTZ = new Date(formatter.format(localDate));
const tzOffset = localDate.getTime() - localDateAtTZ.getTime();
return new Date(localDate.getTime() + tzOffset);
}
and it has the following behavior
getDateInTz("2021-07-01 20:05", "America/Chicago").toISOString(); // 2021-07-02T01:05:00.000Z
getDateInTz(new Date("2021-12-05 20:05"), "America/Chicago").toISOString(); // 2021-12-06T02:05:00.000Z
getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T02:05:00.000Z if local time is NY
getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T07:05:00.000Z if local time is UTC
While the above solution works in Chrome, it doesn't work on Firefox because FF is unable to do Date.parse on the output of formatter.format(). Which leads me to think that it's not a correct solution.
Has anyone run into this requirement before, and have a good solution for it?

As far as I know this is not possible without the help of a library like luxon or day.js
In luxon this would be the way to go
let local = luxon.DateTime.local(); // 2021-10-31T20:26:15.093+01:00
let localInCT = local.setZone("America/Chicago"); //2021-10-31T14:26:15.093-05:00
Have a look at this project using these methods

We're limited by the JavaScript native Date object here.
The internal state of a Date object is the number of milliseconds that have elapsed since 1970-01-01 00:00 UTC, and no timezone is stored in the Date object.
So, we can create Dates somewhat equivalent to ones created in another timezone, but they won't behave exactly the same:
The timezone offset for Date.toString() will show the local client timezone (e.g. GMT+0000) rather than the offset in the desired timezone.
DST rules may not work as expected. We can get the equivalent date for say America/New_York, but DST transitions will obey the local timezone rules and not the New York rules.
Having said that, a variant of the approach you're using will give what I would call equivalent dates in the desired timezone.
How we do this:
First use Date.toLocaleString() to format an ISO timestamp in the desired timezone. We use a hack to do this, passing the 'sv' locale to the function. This will create an ISO timestamp, e.g. yyyy-MM-dd HH:mm:ss.
Pass this timestamp to the Date() constructor.
TLDR: This can't really be done. But for some contexts and use cases we can approximate the desired behaviour. I would recommend using a library like luxon for this purpose.
Example below:
function getDateInTimezone(date, timeZone) {
// Using a locale of 'sv' formats as an ISO date, e.g. yyyy-MM-dd HH:mm.
const timeInTimeZone = date.toLocaleString('sv', { timeZone } );
// Pass this to the Date constructor
return new Date(timeInTimeZone);
}
const localTime = new Date();
const timeZoneList = ['Asia/Tokyo', 'Europe/Berlin','America/Los_Angeles'];
console.log(`Local Time: ${localTime.toLocaleTimeString()}`);
for(let timeZone of timeZoneList) {
const dt = getDateInTimezone(localTime, timeZone);
console.log(`Time (${timeZone}): ${dt.toLocaleTimeString()}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
Timezones in luxon are a lot easier to handle, also when we call .toString() on a Luxon DateTime, we get the correct UTC offset.
const { DateTime } = luxon;
const localTime = DateTime.now();
const timeZoneList = ['Asia/Tokyo', 'Europe/Berlin','America/Los_Angeles'];
console.log(`Local Time: ${localTime.toFormat('HH:mm:ssZZ')}`);
for(let zone of timeZoneList) {
const dt = DateTime.fromMillis(Date.now(), { zone });
console.log(`Time (${zone}): ${dt.toFormat(' HH:mm:ssZZ')}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.0.2/luxon.min.js" integrity="sha512-frUCURIeB0OKMPgmDEwT3rC4NH2a4gn06N3Iw6T1z0WfrQZd7gNfJFbHrNsZP38PVXOp6nUiFtBqVvmCj+ARhw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

You can use something like this:
const actualDate = new Date()
actualDate.toLocaleString('en-US', { timeZone: 'America/New_York' })

Does this solve your question?
function getDateInTZ(date, tz) {
return new Date(date).toLocaleString('en-US', { timeZone: tz })
}
console.log(getDateInTZ("2021-07-01 20:05", "Asia/Kolkata"))
console.log(getDateInTZ("2021-07-01 20:05", "America/Chicago"))
console.log(getDateInTZ("2021-12-06T02:05:00.000Z", "America/New_York"))

let date = new Date();
let time = date.toLocaleTimeString([], { hour12: true })
if we are using hour12 true it will return the time in 12h format else it will return the time in 24h format
make sure we are using TZ on .env file it always been a good practice and helps to erase all the extra code.
you can simply use
TZ=America/New_York

Related

Convert Epoch timestamp to ISO in javascript

I have a function in Java to convert an Epoch date to ISO 8601, but I've come across the need to do it in Javascript. I have it somewhat working in JS but it needs to be localized to the timezone.
Java version:
public static String epochToIso8601(long time, String Zone) {
String format = "yyyy-MM-dd'T'HH:mm:ssX";
TimeZone timeZone = TimeZone.getTimeZone(Zone);
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
sdf.setTimeZone(timeZone);
return sdf.format(new Date(time));
}
Param1: -157737600000
Param2: PST
Output: 1965-01-01T00:00:00-08
My attempt in Javascript:
function epcov(epoch, timezone)
{
var someValueNum = Number(epoch);
var s = new Date(someValueNum);
return s.toISOString();
}
Essentially I want the same thing that's coming out of Java, but it's outputting: 1965-01-01T08:00:00.000Z
By the way, I'm already splitting the date and time up from something that looks like this, so if there is a better to just pass in the following as one string and let Javascript parse it, that would be amazing:
/Date(-157737600000-0800)/
We can convert the string /Date(-157737600000-0800)/ to a unix time (in ms), and a UTC offset in HHMM using String.match().
The HHMM UTC offset can then be converted to a UTC offset in milliseconds by multiplying the HH value by 3600000 and the MM value by 60000.
We then create a new Date object using the unix time and offset values, since we know the exact offset at that point in time.
We then format using Date.toISOString() and replace the 'Z' UTC offset timezone value with the actual UTC offset string (e.g. '-08:00').
function parseAndFormatDate(date) {
const [,millis, offset] = date.match(/([+\-]+\d+)([+\-]+\d+)/);
const offsetMillis = (offset.slice(0, 1) + '1') * (offset.slice(1, 3) * 3600000 + offset.slice(-2) * 60000);
const formattedOffset = offset.slice(0, 3) + ':' + offset.slice(-2);
return new Date(+millis + offsetMillis).toISOString().replace('Z', formattedOffset);
}
console.log(parseAndFormatDate('/Date(-157737600000-0800)/'));
console.log(parseAndFormatDate('/Date(+1664271413000+0100)/'));
.as-console-wrapper { max-height: 100% !important; }
I hope this helps you in some way.
JS doesn't have good (any?!) support for exporting an ISO 8601 string in a specified time zone. So you have to construct the string yourself, manually.
The use of the Swedish locale is to get an ISO 8601-like basis from which to pull the elements of the date time. Unfortunately there is no ISO 8601 formatting locale.
Note that the following will only reliably work with IANA timezone names because timezone abbreviations (PST, CST, BST) can be ambiguous. For example: V8 will accept 'PST' but SpiderMonkey will not.
// Get wall clock date at the specified tz in IS0 8601
const getISO8601Date = (d, timeZone) =>
d.toLocaleString('sv-SE', { timeZone, dateStyle: 'short'})
// Get wall clock time at the specified tz in IS0 8601
const getISO8601Time = (d, timeZone) =>
d.toLocaleString('sv-SE', { timeZone, timeStyle: 'medium'})
// Get time zone offset in specified tz in IS0 8601
const getISO8601TimeZoneOffset = (d, timeZone) => {
const s = d.toLocaleString('sv-SE', { timeZone, timeZoneName: 'longOffset' })
const result = /GMT(?<offset>[+−]\d\d:\d\d)/.exec(s) // Use regexp to pull out offset
return result ? result.groups.offset : 'Z'
}
// Put together an ISO 8601 string representing the wall clock at the specified date, in the specified timezone
const getISO8601Dtg = (instant, timeZone) => {
const d = new Date(instant)
return `${getISO8601Date(d, timeZone)}T${getISO8601Time(d, timeZone)}${getISO8601TimeZoneOffset(d, timeZone)}`
}
// Only reliably accepts IANA timezone names eg. 'America/Los_Angeles'
console.log(getISO8601Dtg(-157737600000, 'America/Los_Angeles')) // 1965-01-01T00:00:00−08:00
Relevant.

Converting date formats without timezone conversion?

I'm trying to do this without adding moment js to my project but it seems more difficult than I'd like.
if I get a date that's formatted as : "2021-07-19T12:15:00-07:00"
Is there an efficient way to have it formatted as:
"12:15 pm"
regardless of where me and my browser are located?
I've gotten as far as some other answers with no luck, for example:
var date = new Date('2021-07-19T12:15:00-07:00')
var userTimezoneOffset = date.getTimezoneOffset() * 60000;
new Date(date.getTime() - userTimezoneOffset);
Thanks!
You could use Date.toLocaleTimeString() to format the time, this will give you the time in the local timezone, if we remove the UTC offset.
There are other options available here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat
let timestampWithUTCOffset = "2021-07-19T12:15:00-07:00";
let timestampWithoutUTCOffset = timestampWithUTCOffset.substr(0,19);
console.log( { timestampWithUTCOffset , timestampWithoutUTCOffset });
let dt = new Date(timestampWithoutUTCOffset);
console.log('Time of day:', dt.toLocaleTimeString('en-US', { timeStyle: 'short' }))

date-fns | How do I format to UTC

Problem
It looks like when I use the format() function, it automatically convert the original UTC time into my timezone (UTC+8). I have been digging through their docs for hours and couldn't seem to find a way to default it to UTC time.
import { parseISO, format } from "date-fns";
const time = "2019-10-25T08:10:00Z";
const parsedTime = parseISO(time);
console.log(parsedTime); // 2019-10-25T08:10:00.000Z
const formattedTime = format(parsedTime, "yyyy-MM-dd kk:mm:ss");
console.log(formattedTime); // 2019-10-25 16:10:00 <-- 8 HOURS OFF!!
I have tried to use the package data-fns-tz and use something like
format(parsedTime, "yyyy-MM-dd kk:mm:ss", {timeZone: "UTC"});
still no luck.
Please help!
Expected Output
2019-10-25 08:10:00
Actual Output
2019-10-25 16:10:00
You were almost there. This works for me:
import { parseISO } from "date-fns";
import { format, utcToZonedTime } from "date-fns-tz";
const time = "2019-10-25T08:10:00Z";
const parsedTime = parseISO(time);
console.log(parsedTime); // 2019-10-25T08:10:00.000Z
const formatInTimeZone = (date, fmt, tz) =>
format(utcToZonedTime(date, tz),
fmt,
{ timeZone: tz });
const formattedTime = formatInTimeZone(parsedTime, "yyyy-MM-dd kk:mm:ss xxx", "UTC");
console.log(formattedTime); // 2019-10-25 08:10:00 +00:00
Behind the scenes
The date-fns[-tz] libraries stick to the built-in Date data type that carries no TZ info.
Some functions treat it as a moment-in-time, but some like format treat it more like a struct of calendaric components — year 2019, ..., day 25, hour 08, ....
Now the trouble is a Date is internally only a moment in time. Its methods provide a mapping to/from calendaric components in local time zone.
So to represent a different time zone, date-fns-tz/utcToZonedTime temporarily produces Date instances which represent the wrong moment in time — just to get its calendaric components in local time to be what we want!
And the date-fns-tz/format function's timeZone input affects only the template chars that print the time zone (XX..X, xx..x, zz..z, OO..O).
See https://github.com/marnusw/date-fns-tz/issues/36 for some discussion of this "shifting" technique (and of real use cases that motivated them)...
It's a bit low-level & risky, but the specific way I composed them above — formatInTimeZone() — is I believe a safe recipe.
I would suggest using the built-in Date util:
const date = new Date("2019-10-25T08:10:00Z");
const isoDate = date.toISOString();
console.log(`${isoDate.substring(0, 10)} ${isoDate.substring(11, 19)}`);
Outputs:
2019-10-25 08:10:00
Not a general solution for any format, but no external libraries required.
Note
The following solution will not work for all time zones, so if timezone accuracy is critical for your application you might want to try something like the answer from Beni. See this link for more info
I had the exact same question today and did some research to see if anyone has come up with anything better since this question was posed. I came across this solution which fit my needs and stylistic preference:
import { format, addMinutes } from 'date-fns';
function formatDate(date) {
return format(addMinutes(date, date.getTimezoneOffset()), 'yyyy-MM-dd HH:mm:ss');
}
Explanation
getTimezoneOffset returns the number of minutes needed to convert that date to UTC. In PST (-0800 hours) it would return 480 whereas for somebody on CST (+0800 hours) it would return -480.
I had the same problem. What I do is remove the timezone from the ISO string and then use that time with date-fns:
let time = "2019-10-25T08:10:00Z".slice(0, -1)
The above is a time with no time zone, and because there is no timezone date-fns assumes the local timezone, so when you do:
format(parseISO(time), 'h:mm a')
you get: 8:10 AM, or whatever format you prefer. You just have to be careful with the string that you are slicing. If its always the same format then it should work.
I did something like this using date/fns and native date methods
import format from 'date-fns/format';
import parseISO from 'date-fns/parseISO';
export const adjustForUTCOffset = date => {
return new Date(
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds(),
);
};
const formatDate = (dateString) = > {
const date = parseISO(dateString);
const dateWithOffset = adjustForUTCOffset(date)
return format(dateWithOffset, 'LLL dd, yyyy HH:mm')
}
Here is how I did it
const now = new Date()
const date = format(
new Date(now.toISOString().slice(0, -1)),
'yyyy-MM-dd HH:mm:ss'
)
I just removed the Z from the ISO string. I'm not sure if it solves this issue though
solution for timestamp
format(utcToZonedTime(timestamp, 'UTC'), 'MM/dd/yyyy hh:mm a', { timeZone: 'UTC' })
I guess
To construct the date as UTC before parsing would be helpful.
import { parseISO, format } from "date-fns";
const time = "2019-10-25T08:10:00Z";
const parsedTime = parseISO(new Date(Date.UTC(time)));
const formattedTime = format(parsedTime, "yyyy-MM-dd kk:mm:ss");
like this.
try
const formatDate = new Date().toISOString().substr(0, 19).replace('T', ' ');

Is there a function to get the UTC date in the Locale String Format?

I want to get the current UTC date in JavaScript, but display it in the local date format (like Date.toLocaleDateString() does).
I first tried to just get the current UTC Date with Date.toUTCString() but that doesn't actually print out in the local format.
I then tried using the options configuration in toLocaleDateString(), but that just printed the local date and not the UTC date in the local format.
e.g. new Date().toLocaleDateString(options = {timeZone: "UTC"})
I then tried formatting using Intl.DateTimeFormat(), but that just gives the same results as Date.toLocaleDateString() does.
If there was a way to get the locale format then I'd be happy to use that format to format the UTC Date, but as far as I can tell there is none.
For example, given the new Date("Sat, 30 Mar 2019 00:27:19 GMT"), In the US, I should print out "3/30/2019", in Europe I should print out "30/3/2019", and so on, for every supported locale.
However, new Date("Sat, 30 Mar 2019 00:27:19 GMT").toLocaleDateString(options = {timeZone: "UTC"}) will print out "3/29/2019" instead.
I also wanted to display a date using localized string settings, like toLocaleDateString() does, but using the date's UTC value, instead of the local time zone.
For example:
I do want the localized string format, but I also want the UTC value instead of the local time zone value. The desired output in this example would be 4/3/2019, instead of 4/2/2019.
I acknowledged #AndersonHappens suggestion, but I have not used it. Here is what I did, instead:
There is a getTimezoneOffset() function, which provides the local time zone offset.
We can use this function result and create a new Date, applying the diff. Then, we can use toLocaleDateString() directly, as usual, to get the date in localized string format:
The solution as a function could be like this:
function toLocaleUTCDateString(date, locales, options) {
const timeDiff = date.getTimezoneOffset() * 60000;
const adjustedDate = new Date(date.valueOf() + timeDiff);
return adjustedDate.toLocaleDateString(locales, options);
}
Given a date, you can get the locale format with new Intl.DateTimeFormat().
You can then use formatToParts in order to get the formatting of the date and each specific component.
Following the example in the formatToParts documentation, I created the following method to get the UTC date in the locale string.
function toLocaleUTCDateString(date) {
let formatter = new Intl.DateTimeFormat();
return formatter.formatToParts(date).map(({type, value}) => {
switch (type) {
case 'day': return date.getUTCDate();
case 'hour': return date.getUTCHours();
case 'minute': return date.getUTCMinutes();
case 'month': return date.getUTCMonth() + 1;
case 'second': return date.getUTCSeconds();
case 'timeZoneName': return "UTC";
case 'year': return date.getUTCFullYear();
default : return value;
}
}).reduce((string, part) => string + part);
}
Do note however that this method does not remember number versus string formatting. For example, if you want to display the month of March as "March" (or the specific language month string), and not as the number 3, you would have to figure out how to do that yourself. It also doesn't handle discrepancies in weekdays, so if the local date is "Friday" and the UTC Date is "Saturday", you would have to figure that out separately as well.
You almost got it right - the timeZone option is available in the second argument. The first argument to toLocaleDateString is for the locales.
This example from your question works when options are the second argument (and is much simpler than other answers):
const usLocale = 'en-US'
new Date('Sat, 30 Mar 2019 00:27:19 GMT').toLocaleDateString(usLocale, {
timeZone: 'UTC',
})
// '3/30/2019'
const ukLocale = 'en-GB'
new Date('Sat, 30 Mar 2019 00:27:19 GMT').toLocaleDateString(ukLocale, {
timeZone: 'UTC',
})
// '30/03/2019'
var dateToPrint = new Date(Date.UTC(2020, 3, 23, 15, 0, 0));
new Date(
dateToPrint.getUTCFullYear(),
dateToPrint.getUTCMonth(),
dateToPrint.getUTCDate(),
dateToPrint.getUTCHours(),
dateToPrint.getUTCMinutes(),
dateToPrint.getUTCSeconds()
).toLocaleString('es-ES')
see image
Inside the toLocaleDateString you can pass options. There is an option name TimeZone. You have to set it to 'UTC'
const dateToParse = new Date()
dateToParse.toLocaleDateString(locate, { timeZone: 'UTC' })
Check out Intl.DateTimeFormat on MDN!
Using it is as simple as
// do this once in a central library file
const formatter = new Intl.DateTimeFormat('en', {
timeZone: 'UTC',
timeZoneName: 'short',
month: 'short',
day: '2-digit',
hour12: false,
hour: '2-digit',
minute: '2-digit',
})
// reuse anywhere for consistency
const myDate = new Date(
'Thu Feb 10 2022 12:50:14 GMT+0100'
)
formatter.format(myDate) === 'Feb 10, 11:50 UTC' // true
Open your console, copy-paste the code and start playing!
Again, Intl.DateTimeFormat on MDN.
Enjoy!
toLocaleString receives some parameters, the first parameter is the locale. To solve your issue specifically, you need to understand that UTC is not a locale. What you could to to accomplish what you want is to pass either 'en-US' for 3/29/2019 and 'en-GB' for 29/03/2019 hope that helps!

How do I convert a Firestore date/Timestamp to a JS Date()?

I am trying to convert the below date to a javascript Date() object. When I get it back from the server, it is a Timestamp object,
Screenshot from Firebase Firestore console:
When I try the following on a list of objects returned from firestore:
list.forEach(a => {
var d = a.record.dateCreated;
console.log(d, new Date(d), Date(d))
})
I get this output:
Clearly the Timestamps are all different, and are not all the same date of Sept 09, 2018 (which happens to be today). I'm also not sure why new Date(Timestamp) results in an invalid date. I'm a bit of a JS newbie, am I doing something wrong with the dates or timestamps?
The constructor for a JavaScript's Date doesn't know anything about Firestore's Timestamp objects — it doesn't know what to do with them.
If you want to convert a Timestamp to a Date, use the toDate() method on the Timestamp.
You can use toDate() function along with toDateString() to display the date part alone.
const date = dateCreated.toDate().toDateString()
//Example: Friday Nov 27 2017
Suppose you want only the time part then use the toLocaleTimeString()
const time = dateCreated.toDate().toLocaleTimeString('en-US')
//Example: 01:10:18 AM, the locale part 'en-US' is optional
You can use Timestamp.fromDate and .toDate for converting back and forth.
// Date to Timestamp
const t = firebase.firestore.Timestamp.fromDate(new Date());
// Timestamp to Date
const d = t.toDate();
How to convert Unix timestamp to JavaScript Date object.
var myDate = a.record.dateCreated;
new Date(myDate._seconds * 1000); // access the '_seconds' attribute within the timestamp object
Please use toDate() method and then convert it into the format using angular pipe like this -
{{ row.orderDate.toDate() | date: 'dd MMM hh:mm' }}
apart from other answers you can do it like this as well
//date from firebase is represented as
let time = {
seconds: 1613748319,
nanoseconds: 47688698687,
}
const fireBaseTime = new Date(
time.seconds * 1000 + time.nanoseconds / 1000000,
);
const date = fireBaseTime.toDateString();
const atTime = fireBaseTime.toLocaleTimeString();
console.log(date, atTime);
At last, I could get what I need. This returns date as 08/04/2020
new Date(firebase.firestore.Timestamp.now().seconds*1000).toLocaleDateString()
const timeStampDate = record.createdAt;
const dateInMillis = timeStampDate._seconds * 1000
var date = new Date(dateInMillis).toDateString() + ' at ' + new Date(dateInMillis).toLocaleTimeString()
OutPut Example: Sat 11 Jul 2020 at 21:21:10
This might help:
new Date(firebaseDate._seconds * 1000).toUTCString()
A simple way is to convert firestore timestamp to epoch timestamp is by using toMillis() method on firestore timestamp.
For example:
You have a firestore timestamp
created_on : Timestamp { _seconds: 1622885490, _nanoseconds: 374000000 }
let epochTimestamp = created_on.toMillis()
//epochTimestamp = 1621081015081
//Now this timestamp can be used as usual javascript timestamp which is easy to manipulate.
let date = new Date(epochTimestamp) //date = Sat May 15 2021 17:46:55 GMT+0530 (India Standard Time)
The timestamp object you get from firestore has a toDate() method you can use.
list.forEach(a => {
var d = a.record.dateCreated;
console.log(d.toDate())
})
Here's a quote from firebase docs about the toDate() method
Convert a Timestamp to a JavaScript Date object. This conversion
causes a loss of precision since Date objects only support millisecond
precision.
Returns Date JavaScript Date object representing the same point in
time as this Timestamp, with millisecond precision.
https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp#todate
This works for me.
new Date(firebaseDate.toDate())
This works for me
let val = firebase.timestamp // as received from the database, the timestamp always comes in an object similar to this - {_nanoseconds: 488484, _seconds: 1635367}
(new Date( (val.time._seconds + val.time._nanoseconds * 10 ** -9) * 1000)).toString().substring(17, 21)
Lots of answer here, but as a rookie I found most of them confusing.
So for rookies like me, here is a simple explanation of how to convert a Firestore date/Timestamp to a Javascript Date() and why you need to.
Why convert?
Firestore stores Dates as a Timestamp object. This is not the same as a Javascript Date() object.
This was confusing to me because if you send a Date() object to Firestore, and then retrieve it, it will hand you back a Timestamp object. Like if you hand Firestore a dollar, it will hand you back 4 quarters. It is the same amount of money (or same date), but if you were expecting paper, and got metal, you would be confused.
How to convert
Luckily the Timestamp object has functions built into do give you a Javascript Date object: toDate
Note: Remember, toDate looks like the Javascript toLocaleDateString() or toDateString() but it is not. A JS Date() object and Firestore Timestamp object are not the same so don't make my rookie mistake of trying to use functions from one, on the other.
To convert a Firestore Timestamp into a Javascript date, just call .toDate() on the Timestamp.
//get the document from Firestore
let fireStoreTimestamp = doc.data().nameOfYourDateField;
let javascriptDate = fireStoreTimestamp.toDate();
You can use the dayjs library to convert firebase firestore timestamp seconds to your local time.
newDate = dayjs.unix(date.seconds).$d;
It will take
date: {
seconds: 1639506600,
nanoseconds: 0
}
and convert it to
Date Sat Nov 16 2019 00:00:00 GMT+0530 (India Standard Time)
To help those still looking around for an answer to convert Firestore Date to JS Date to display in the web app. Here goes an example using typescript...
import {
Timestamp,
} from "firebase/firestore";
interface IStuff {
createdAt: Timestamp;
}
const insertStuff = async (text: string) => {
await addDoc(collection(db, "coolstuff"), {
text,
createdAt: serverTimestamp(),
});
};
<p>{item.createdAt?.toDate().toDateString()}</p>
// OR
<p>{item.createdAt?.toDate().toLocaleTimeString()}</p>
Extending Waleed Tariq answer, to get a more readable string:
function formatDate(date) {
const formatDate = new Date(
date.seconds * 1000 + date.nanoseconds / 1000000
);
return formatDate.toLocaleTimeString('en-us', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
}
const timeStamp = {nanoseconds: 184000000, seconds: 1664826910};
console.log(formatDate(timeStamp))
I had the same problem. And i figured out like this:
const createdAt = firebase.firestore.Timestamp.fromDate(new Date());
// then using dayjs library you can display your date as you want.
const formatDate = dayjs.unix(createdAt.seconds).format('YYYY-MM-DD');
Output should look like e.g. 2020-08-04
If you want don't want to lose the milliseconds you can do the following:
var myDate = a.record.dateCreated;
new Date((myDate.seconds + myDate.nanoseconds * 10 ** -9) * 1000);
i work in angular.
i have an interface and a field date: Date.
the angular pipe date no work: order.date | date:'medium'
i change type of field date in interface
date: firebase.firestore.Timestamp
the angular pipe date work, but with function toDate()
order.date.toDate() | date:'medium'
It's very simple really. Use this simple epoch converter function which converts epoch seconds into Javascript date and time.
function getUNIXTime(dt) {
let unix = new Date(dt * 1000);
return unix.toUTCString().slice(5, 16);
}
Pass the timestamp.seconds into this function then slice it according to your needs to get a string of text with date and time.
Normally using any type (i.e. loginDate:any) and toDate() worked without problem in my all projects. But in my last project it didn't. I saw seconds in Timestamp object is _seconds anymore (Firebase 8.6.8). This type of change may have affected it. I don't know but i had no time so i used an alternative solution. A custom pipe. It can be used as an alternative:
import { Pipe, PipeTransform } from '#angular/core';
import { formatDate } from '#angular/common';
#Pipe({
name: 'timestamp'
})
export class TimestampPipe implements PipeTransform {
transform(value: any, format?: string) {
if (!value) { return ''; }
if (!format) { format = 'dd MMM yy'; }
return formatDate(value._seconds * 1000, format, 'tr');
}
}
and
{{ item.endDate | timestamp}}
P.S. Type is not important with this pipe. Worked with loginDate:any or loginDate:Date well.
to store timestamp into firestore:
import * as firebaseAdmin from "firebase-admin";
const created = firebaseAdmin.firestore.FieldValue.serverTimestamp();
// type
created: FirebaseFirestore.Timestamp | FirebaseFirestore.FieldValue | undefined;
To read back as a js Date object
const createDate = (created as FirebaseFirestore.Timestamp).toDate();
To read back as RFC3339 string
const createDate = (created as FirebaseFirestore.Timestamp).toDate().toISOString();
Web Firestore Timestamp:
function dateToFirestoreTimestamp(dateString = ''){
var timestampDate = new Date(); // this will return current date-time
if(dateString != ''){
// this will return timestamp according to provided date-time
dateString = dateString.replace(' ', 'T');
timestampDate = new Date(dateString);
}
timestampDate = firebase.firestore.Timestamp.fromDate(timestampDate);
return timestampDate;
}
This is by far the most elegant, precise and easiest way to convert a firebase-timestamp to a date (no dependenceis etc. needed)
const date = new Intl.DateTimeFormat(
'de-De', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}
).format(firebaseTimeStamp.toDate())
Here is a cheatsheet with all necesarry parameters
this is the different thing between firestore timestamp and Javascript Date() object. if you want to use javascript Date() object from firestore timestamp, this is what I do:
const foo = new Date(firestoreTimestamp.toDate());
then you can use the javascript Date() object, as usual. here are some references:
https://www.w3schools.com/jsref/jsref_obj_date.asp
For example, we want to retrieve the date from the Date() object with string format:
const foo = new Date(firestoreTimestamp.toDate());
foo.toLocaleDateString();
etc.

Categories