2

I have a function where I convert a date string or a datetime string into a date object with time set to 00:00:00 - basically truncating the time.

/**
 * @param dateString - can either be 2023-07-13 or 2023-07-13 03:03:03
 */
const removeTime = (dateString: string): Date | undefined => {
    if (isValid(new Date(dateString))) {
        const timestamp = new Date(dateString);

        console.log('PARAM', dateString);
        console.log('NATIVE', timestamp);
        console.log('BEFORE TRUNCATE', format(timestamp, Constants.FORMAT_DATE));
        console.log(
            'AFTER TRUNCATE',
            format(
                new Date(timestamp.getFullYear(), timestamp.getMonth(), timestamp.getDate()),
                Constants.FORMAT_DATE
            )
        );

        return new Date(timestamp.getFullYear(), timestamp.getMonth(), timestamp.getDate());
    } else {
        return undefined;
    }
};

Please note that both the isValid and format calls are coming in from date-fns.

My problem is that the new Date(dateString) call sets the day back by 1.

PARAM:           2023-07-13
NATIVE:          Wed Jul 12 2023 18:00:00 GMT-0600 (Mountain Daylight Time)
BEFORE TRUNCATE: 2023-07-12
AFTER TRUNCATE:  2023-07-12

My Constants.FORMAT_DATE is yyyy-MM-dd.

ADDITIONAL INFO

It looks like this is only an issue if the dateString doesn't have a time part to it (i.e. 2023-07-13). The function actually works just fine if the string contains a time (i.e. 2023-07-13 03:03:03).

PARAM:           2023-07-13 11:26:11
NATIVE:          Thu Jul 13 2023 11:26:11 GMT-0600 (Mountain Daylight Time)
BEFORE TRUNCATE: 2023-07-13
AFTER TRUNCATE:  2023-07-13
dokgu
  • 4,957
  • 3
  • 39
  • 77

1 Answers1

1

You should add the timezone offset:

const isValid = dt => !isNaN(+dt);

const removeTime = (dateString) => {
    const dt = new Date(dateString);
    if (!isValid(dt )) {
      return;
    }
    dt.setMinutes(dt.getMinutes() + dt.getTimezoneOffset());
    return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate());
};

console.log(removeTime('2023-07-13').toString());
console.log(removeTime('2023-07-13 03:03:03').toString());
Alexander Nenashev
  • 8,775
  • 2
  • 6
  • 17
  • 1
    Out of curiosity, why are you creating a date from a string then convert it back to string just to create another date object? – dokgu Jul 13 '23 at 19:02
  • @dokgu it cuts the time part, but you can create it as you did in your question, seems better. that was just a quick hack – Alexander Nenashev Jul 13 '23 at 19:03
  • Sorry but I plugged your code into a [fiddle](https://jsfiddle.net/8hu3vfwm/) and it's giving me the day before. – dokgu Jul 13 '23 at 19:06
  • Your first console log shows July 12 instead of 13. – dokgu Jul 13 '23 at 19:26
  • @dokgu damn, fixed again :) – Alexander Nenashev Jul 13 '23 at 19:26
  • Not really - now it shows both as 12 instead of both being 13. – dokgu Jul 13 '23 at 19:27
  • @dokgu damn, we need to add not substract timezone offset, working now... sorry for troubles, i'm almost asleep :) – Alexander Nenashev Jul 13 '23 at 19:30
  • @dokgu seems works perfect now, don't forget to accept and upvote, thanks – Alexander Nenashev Jul 13 '23 at 19:32
  • Is this going to work regardless of where the user is situated? I want this function to work regardless of the timezone the user is located in. – dokgu Jul 13 '23 at 19:32
  • Thank you! I appreciate the quick responses! – dokgu Jul 13 '23 at 19:38
  • @dokgu you are welcome, mate, don't forget to upvote if not already, thanks :) – Alexander Nenashev Jul 13 '23 at 19:39
  • 1
    This might "work", but it's inefficient and circuitous logic that is much simplified by manually parsing the string, e.g. `let [y,m,d] = dateString.split(/\D/) || []; let date = new Date(y, m-1, d);` is more efficient, less code and clearer logic. – RobG Jul 14 '23 at 03:33
  • 1
    *dateString* should be tested for validity before being parsed by the built–in parser. Many will parse invalid timestamps to a valid *Date*, so checking afterward is closing the barn door after the horse has bolted. – RobG Jul 14 '23 at 03:35
  • 1
    "*When you parse a date string you get a date in UTC,*" is wrong. The built–in parser creates a time value, which is a millisecond offset from the ECMAScript epoch. It is output formatting (*toString*, *toISOString*, *toLocaleString*, etc.) that determines whether the resulting timestamp is UTC or based on a timezone. – RobG Jul 14 '23 at 03:38
  • @RobG in my experience strings dates came in unexpected formats so i've checked whether they contain a timezone with regular expressions. the solution here is simplified – Alexander Nenashev Jul 14 '23 at 09:37
  • @RobG i've just fixed the timezone offset, nothing more – Alexander Nenashev Jul 14 '23 at 09:44