1

I have a Spring application and i receive a date from an angular client as a String, how can i convert this date to a Java Date, following is the TypeScript Date format :

TypeScript Date Format : Mon Jan 04 2021 00:00:00 GMT+0100 (Central European Standard Time)

Java Date Format : Mon Jan 04 00:00:00 CET 2021

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
Bilal Dekar
  • 3,200
  • 4
  • 28
  • 53
  • 2
    Why don't you use the standard ISO datetime format? The formats above seem to be for humans to read easily, not for data transfer. – marstran Jan 04 '21 at 14:14
  • 2
    There is no one single Java date format. DateTimeFormatter exists for precisely the reason of parsing and printing pratically any imaginable format. – Michael Jan 04 '21 at 14:14
  • 1
    You've already used the correct term: date format. If you have a look at Java's date api there's a lot of documentation how you can use date formats to _parse_ a date string into a date object or how to _format_ a date object to a string. – Thomas Jan 04 '21 at 14:15
  • If by *Java Date* you meant `java.util.Date`, don’t use that class. It is poorly designed and long outdated. Instead use `Instant` or `ZonedDateTime`; both classes are from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Jan 04 '21 at 19:28

3 Answers3

2

java.time

how can i convert this date to a Java Date, following is the TypeScript Date format :

TypeScript Date Format : Mon Jan 04 2021 00:00:00 GMT+0100 (Central European Standard Time)

java.time provides you with DateTimeFormatterBuilder using which you can define a complex format for parsing/formatting as shown below:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.util.HashSet;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "Mon Jan 04 2021 00:00:00 GMT+0100 (Central European Standard Time)";
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                    .parseCaseInsensitive()
                                    .appendPattern("EEE MMM dd uuuu HH:mm:ss")
                                    .appendLiteral(" ")
                                    .appendZoneRegionId()
                                    .appendOffset("+HHmm", "Z")
                                    .appendLiteral(" (")
                                    .appendZoneText(TextStyle.FULL)
                                    .appendLiteral(")")
                                    .toFormatter(Locale.ENGLISH);
        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
        System.out.println(zdt);
    }
}

Output:

2021-01-04T00:00+01:00[Europe/Paris]

Java Date Format : Mon Jan 04 00:00:00 CET 2021

A date-time object is supposed to store the information about the date, time, timezone etc., not about the formatting. You can format a date-time object into a String object with the pattern of your choice using date-time formatting API.

  • The date-time formatting API for the modern date-time types is in the package, java.time.format e.g. java.time.format.DateTimeFormatter, java.time.format.DateTimeFormatterBuilder etc.
  • The date-time formatting API for the legacy date-time types is in the package, java.text e.g. java.text.SimpleDateFormat, java.text.DateFormat etc.

Given below is how you can format zdt (obtained above) into a custom format:

DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
String strDateTimeFormatted = zdt.format(dtfOutput);
System.out.println(strDateTimeFormatted);

Output:

Mon Jan 04 00:00:00 CET 2021

Learn about the modern date-time API from Trail: Date Time.

In case you want to convert zdt (obtained above) into java.util.Date, you can do so as shown below:

Date date = Date.from(zdt.toInstant());
System.out.println(date);

A note about the legacy date-time API:

The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the milliseconds from the Epoch of January 1, 1970. When you print an object of java.util.Date, its toString method returns the date-time calculated from this milliseconds value. Since java.util.Date does not have timezone information, it applies the timezone of your JVM and displays the same. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFomrat and obtain the formatted string from it. 3. The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • It works on my Java 11 (not on my Java 8). I am wondering a bit. I was thinking that `appendZoneRegionId()` would cause `GMT` to be parsed as a time zone, and `appendZoneText(TextStyle.FULL, new HashSet<>())` `Central European Standard Time` to be parsed as a conflicting time zone, so I would expect an exception but get none. It also works with the one-arg `appendZoneText()`: just `.appendZoneText(TextStyle.FULL)`. – Ole V.V. Jan 04 '21 at 21:01
  • Thanks, @OleV.V. for the valuable information which will be useful for future visitors of this page. – Arvind Kumar Avinash Jan 04 '21 at 22:52
  • yes it works, thank you for the detailed solution. – Bilal Dekar Jan 05 '21 at 10:40
1

Mon Jan 04 2021 00:00:00 GMT+0100 (Central European Standard Time)

This is an ambiguous timestamp. Political entities and the world at large is free to redefine what CEST means, at which point GMT+0100 means one thing, and CST means another. Furthermore, CEST has implications for any 'math' done on this date that are different from GMT+0100.

For example, if I want to know the date 6 months from that one, then if CST is leading, you'd want:

Thu Jul 04 2021 00:00:00 GMT+0200 (Central European Daylight Time)

or possibly you'd want that time but one hour earlier - another open question, there is no clear answer to that question inherent in the idea 'add 6 months to this timestamp', so you will have to specify it, because otherwise you get some random guess by the system, and you almost never want your computer / programming language to guess at a 50/50 concept like this.

If GMT+0100 is leading, you end up with:

Thu Jul 04 2021 00:00:00 GMT+0100 (Central European Standard Time)

Which is completely bizarre there are zero places on the entire planet where this timestamp makes sense as printed: Nobody is on CEST on the 4th of july, anywhere. It's a timestamp that is 'real', and yet used by literally 0 people.

Thus, before continuing, first you need to ask yourself which bits and bobs from what you do have, you want to preserve when you convert it. Note that there are 3 different ideas of time:

  • 'solarflares' time: Commonly measured as millis-since-epoch. This is devoid of human concepts such as timezones. To record the exact instant in time that an event happened, or will happen, if the event is not a human appointment (i.e. when a solarflare is predicted to happen or did happen, hence the name 'solarflares' time). In java, best represented by java.time.Instant.

  • 'appointment' time: Commonly measured as a big sack of numbers: A year, a month, a day, hour, minute, second, and a timezone. And not one of those GMT+0100 useless zones, but something like Europe/Amsterdam. Something like Central European Standard Time is somewhat common, but also a very bad idea. These names have no clear meaning, something like Europe/Amsterdam is designed to most likely always have clear meaning, that's a proper zone. The idea is: Let's say you make an appointment with your dentist, in Amsterdam, for next month. It sure seems like a solarflares kind of deal, but it is not: if the netherlands decides to join a different timezone, the absolute # of seconds until your appointment changes along. Whereas that solarflare is not going to occur an hour earlier just because some political entity decreed it so.

  • 'alarm' time: Like appointment time but no zone info as a fundamental. If you set your alarm to wake you up at 8 in the morning and you hop in a plane and fly west a bunch, you want the alarm to still go off at 8 in the morning local time: The # of seconds until the alarm goes off should change as you move across zones.

So, what is your time value intended to represent?

If 'solarflares' time.

Then the job is to first convert this into a java.time.Instant object, and take it from there. For example, convert back to appointment time via .atZone(), and then print it to a string that looks like that using a java.time.format.DateTimeFormatter. Imagine the input was in singapore time instead, then with this strategy the output is still in CET. Also, I get the feeling you showed the string not because you need the string to be formatted like that, but because you erroneously think that java stores time in this string format. It doesn't; java stores appointment time as an object with a field for year, month, day, etc. The printing of this to a string is separated out, and controlled by a formatter. You can make a formatter to print it any way you please.

Parsing this to a j.t.Instant value can be done based on the GMT+0100, you can ignore the CEST trailing text.

If 'appointments' time.

Then you need to parse this out which is non-trivial; the GMT+0100 is not what you wanted, that IS a legal zone, but not a useful one (no country in the CEST zone uses GMT+0100. There are places on the planet that are GMT+0100 year round. They are not, however, anywhere near central europe). Thus, the relevant bits are everthing except GMT+0100, including CEST, and that is not a standard date format, and 'Central European Standard Time' is not a thing java.time can recognize as far as I know. You'll need a table of all the possible strings that typescript can generate at that point.

If 'alarm time'

Then you can just stop parsing after the final :00 and toss the rest. Use a regexp to strip it out, then parse into a LocalDateTime using the LocalDateTime.of(stringValue, formatter) method. Easy enough.

A note of advice

Try to course your TypeScript to print this stuff in something other than that. One great way to do it is to combine solarflares time with an explicit zone (like Europe/Amsterdam, not like Central European Standard Time). This is much more easily reparsed into any of the 3 different conceptual ways to refer to time.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • No, as timestamp it is unambiguous. You mention CEST, but that is usually for Central European Summer Time, so irrelevant here (January or not). You are correct that how to do date math on it, like adding 6 months, is undefined, but this also wasn’t asked. – Ole V.V. Jan 04 '21 at 19:59
  • @OleV.V. `ZoneId.of("Europe/Amsterdam")` is not the same as `ZoneOffset.ofHours(1)`. Thus, ambiguous. You can do date math on dates, it's inherent. Thus complicating conversion. I regret that I can't make date/time stuff any easier for you. – rzwitserloot Jan 04 '21 at 20:30
0

You can use epoch time to share time between client and server, it´s an easy way.

Typescript epoch time management

const epoch = new Date().getTime();
console.log(epoch);

const date = new Date(epoch);
console.log(date);

Result:

1609801111672

Date Mon Jan 04 2021 22:58:31 GMT+0000 (Western European Standard Time)

Java epoch time management with java.util.Date

long epoch = new Date().getTime();  
log.debug( "Epoch: {}", epoch );
        
Date date = new Date(epoch);    
log.debug( "Date: {}", date );

Result

Epoch: 1609801111672

Date: 2021-01-04T22:58:31.672Z
Luis Costa
  • 1,150
  • 7
  • 8