3

I am working on an Angular project using FireStore database and I have the following problem:

Into my Firestore database a I have documents like this:

enter image description here

As you can see in the previous pic the start and end fields are defined on Firestore as TimeStamp fields.

Into a service class I retrieve all these documents in this collection and I return these documents as a list of Observable by this method:

getEvents(): Observable<any[]> {
    this.items = this.db.collection('calendar').valueChanges();

    return this.items;
 }

Then into the ngOnInit() method of my component class I do:

ngOnInit() {

    this.eventService.getEvents().subscribe(events => { this.events = events.map((event) => {

    console.log("START: ", event.start);
    //var date = new Date(event.start);
    var date = new Date(0); // The 0 there is the key, which sets the date to the epoch
    date.setUTCSeconds(event.start);

    var hour = date.getHours();

    console.log("START DATE: ", date);
    console.log("START HOUR: ", hour);
    // ...
}

and here my problem: the value of the event.start is not a date but an object like this (this is the console.log() output):

START:  t {seconds: 1487257200, nanoseconds: 0}

From what I know this object represents my date but how can I convert it again into a Date object.

As you can see I tried doing in this way:

var date = new Date(0); // The 0 there is the key, which sets the date to the epoch
date.setUTCSeconds(event.start);

but doing in this way I am obtaining a wrong date, in fact I am obtaining:

START DATE:  Sun Feb 16 3986 07:00:00 GMT-0800 (Ora standard del Pacifico USA)

the month and the day (Feb 16) are correct but the year is totally wrong (3986 instead 2017).

What is wrong? What am I missing? What is the correct way to obtain a Date object from the retrieved Firestore Timestamp?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
AndreaNobili
  • 40,955
  • 107
  • 324
  • 596
  • 3
    Does this answer your question? [How do I convert a Firestore date/Timestamp to a JS Date()?](https://stackoverflow.com/questions/52247445/how-do-i-convert-a-firestore-date-timestamp-to-a-js-date) – MauriceNino Jul 02 '20 at 12:00
  • @MauriceNino It works fine thanks !!! I take the opportunity to ask you a question (consider that I am very new in JS\TypeScript, I came from Java). If I was in Java doing event.start. and then pressing the TAB on my IDE I would have gotten the list of all the possible method that I can apply on the "event.start" object (included this toDate() method). Doing this in my TypeScript code it doesn't happen. I can't obtain this toDate() method as possible method applicable on my "event.start" object. Why? – AndreaNobili Jul 02 '20 at 12:32
  • That's because your object doesn't have a type yet. I don't know if there is typing for Firebase timestamps, but you could write it yourself. I would like to give you a more detailed answer, but the comment section doesn't allow me to do so. But your method is returning an `any` array. Which means that it could be anything so you can't get typing for EVERYTHING. You would have to type it right. Like returning `Timestamp[]` instead if that exists. – MauriceNino Jul 03 '20 at 09:27
  • I will illustrate that better in an answer – MauriceNino Jul 03 '20 at 09:29

3 Answers3

3

because firestore timestamp is actually different from normal JS Date().

in order to get JS date from timestamp you can use the method that firestore has on its timestamps.

in your code:

event.start should be event.start.toDate()

PS. for your IDE to know the methods that work on that object. Typescript must know the type of object it is. so for example if you are using AngularFire and you make a call to get a document then the type will already be there and your IDE will show available methods. But if the object type is generic like "any" then your IDE wont give available methods. and might throw an error like "method doesn't exist on type any"

Mohamed Aljamil
  • 389
  • 1
  • 9
2

You can use the Timestamps toDate() function and map the observable including arrays to Dates and return those objects:

// Create a custom type to tidy it up. Would recommend creating that in another file. 
// Here more on type aliases: https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-aliases

type ReturnType = {start: Date, end: Date, title: string};

// Change the function to return the created type

getEvents(): Observable<ReturnType[]> {
    this.items = this.db.collection('calendar').valueChanges()
        .pipe(map(tArr => // Use pipe to transform an observable or subject to something else, without subscribing. Check out: https://rxjs-dev.firebaseapp.com/guide/operators
            tArr.map(t => { // Map the array of objects including Timestamps to dates
                t.start = t.start.toDate();
                t.end = t.end.toDate();
                return t;
            })
        )) as Observable<ReturnType[]>;

    return this.items;
}
MauriceNino
  • 6,214
  • 1
  • 23
  • 60
1

You construct you JS Date incorrectly. Correct way to create date is passing milliseconds to it.

var date = new Date(event.start.seconds * 1000);
Ilia Komarov
  • 623
  • 3
  • 6