Talend: Timezone java - java

I am trying to learn Talend Open Studio. I have a column with strings like "2019-09-17 08:42:09 +0400" and I want to convert this with java components and not with tmap to a datetime but with the "+0400" added to my time. I tried a lot of things like LocalDate but it didn't work.
Please if anyone knows how to do it I will appreciate it.Thanks a lot.

To parse date in a given format you can use SimpleDateFormat.
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
Date date = format.parse("2019-09-17 08:42:09 +0400"); // from string to date
String dateAsString = format.format(date); // from date to string

java.time
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendLiteral(' ')
.appendOffset("+HHmm", "+0000")
.toFormatter();
String stringFromTalendCol = "2019-09-17 08:42:09 +0400";
OffsetDateTime javaDateTime = OffsetDateTime.parse(stringFromTalendCol, formatter);
System.out.println(javaDateTime);
The output from this snippet is:
2019-09-17T08:42:09+04:00
If you’re into brevity of code, the formatter may alternatively be defined in just one line:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss xx");
My taste is for reusing the building blocks that java.time offers, which is why I presented the longer option first. The result is the same in both cases.
LocalDate is not enough
You mentioned that you tried LocalDate. A LocalDate is a date without time of day and without time zone or offset from UTC, so it cannot represent the date and time from your question, which may be one reason why your attempts didn’t work.
Your string has a date, a time of day and a UTC offset. OffsetDateTime is the exactly correct class for representing this information.
The offset of +0400 means that an offset of 4 hours 0 minutes has been added to the time compared to UTC. So your point in time is equivalent to 2019-09-17T04:42:09Z, where Z denotes UTC or offset zero.
Link
Oracle tutorial: Date Time explaining how to use java.time.

Related

I have to get OffsetDateTime from a string

String is in this format - "2021-07-13 05:22:18.712"
I tried using this code to parse it.
OffsetDateTime parsedDateTime = OffsetDateTime.parse("2021-07-13 05:22:18.712");
But i keep getting this error -
org.threeten.bp.format.DateTimeParseException: Text '2021-07-13 05:22:18.712' could not be parsed at index 10.
How do i make it work? Any suggestions will be helpful. Thanks
You need to decide on a time zone (or at least on an offset, but time zone is usually the correct means). And then you need to use a formatter that defines the format that you are trying to parse:
private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter(Locale.ROOT);
With this formatter it’s a pretty simple operation:
ZoneId zone = ZoneId.of("Asia/Kolkata");
String input = "2021-07-13 05:22:18.712";
OffsetDateTime dateTime = LocalDateTime.parse(input, FORMATTER)
.atZone(zone)
.toOffsetDateTime();
System.out.println(dateTime);
Output from the example snippet is:
2021-07-13T05:22:18.712+05:30
Since as #Sweeper noted in a comment your string does not contain UTC offset nor time zone, parse it into a LocalDateTime first. The Local in some java.time class names means without time zone or UTC offset. Then convert into a ZonedDateTime in the intended time zone and further into the desired type, OffsetDateTime.
If you want to use the default time zone of the JVM, set zone to ZoneId.systemDefault(). Be aware that the default time zone may be changed at any time from another part of your program or another program running in the same JVM, so this is fragile.
Possible shortcuts
My formatter is wordy because I wanted to reuse as much as I could from built-in formatters. If you don’t mind building the formatter by hand from a pattern, you may use:
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS", Locale.ROOT);
Or even shorter, you may hand substitute the space in your string with a T to obtain ISO 8601 format and then parse into a LocalDateTime without specifying any formatter at all.
What went wrong in your code?
The exception message you got is trying to be helpful:
But i keep getting this error -
org.threeten.bp.format.DateTimeParseException: Text '2021-07-13
05:22:18.712' could not be parsed at index 10.
Index 10 in your string is where the space between date and time is. The one-arg OffsetDateTime.parse method expects ISO 8601 format, like 2021-07-13T05:22:18.712+05:30, so with a T to denote the start of the time part and with a UTC offset at the end. The absence of the T caused your exception. Had you fixed that, you would have got another exception because of the missing UTC offset.
Link
Wikipedia article: ISO 8601
You first need to check the document.
It indicates parse need to go with a date format such as 2007-12-03T10:15:30 +01:00.
You date is missing a "T", "2021-07-13 05:22:18.712". Hence it did not go well, counting it from index 0, it's character at 10.
If you need to parse 2021-07-13T05:22:18.712, you will still get error. An error Text '2021-07-13T05:22:18.712' could not be parsed at index 23. Which is the problem of miliseconds.
So a big round to go:
//Format to date
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
//Format to new string
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
java.util.Date date1=simpleDateFormat.parse("2021-07-13 05:22:18.712");
String newDate = formatter.format(date1);
//finally.
OffsetDateTime parsedDateTime = OffsetDateTime.parse(newDate);

How to format Simple Date Formatter in Java as dd-3 letter month-yyyy?

I have a simple date formatter with the following format:
private static final String DATE_FORMAT = "yyyy-MM-dd";
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT);
//accessExpiryDate is a Date object
DATE_FORMATTER.format(accessExpiryDate);
And it is formatting the date as yyyy-MM-dd. But I want to format the date such as "1 Jun 2019". day + first 3 letter of the month + year.
How can i achieve that? Is there a simple way/method/class or should i write my custom date formatter method?
java.time
Don’t use Date and SimpleDateFormat. Those classes are poorly designed and long outdated, the latter in particular notoriously troublesome. As Jon Skeet said, move to java.time, the modern Java date and time API, for a better experience.
DateTimeFormatter dateFormatter
= DateTimeFormatter.ofPattern("d MMM u", Locale.ENGLISH);
LocalDate ld = LocalDate.of(2019, Month.JUNE, 1);
System.out.println(ld.format(dateFormatter));
Output from this snippet is:
1 Jun 2019
A number of format pattern letters including M for month can yield either a number or a text depending on how many letters you put in the format pattern string (this is true for both DateTimeFormatter and the legacy SimpleDateFormat). So MM gives you two-digit month number, while MMM gives you a month abbreviation (often three letters, but could be longer or shorter in some languages).
If you are getting an old-fashioned Date object from a legacy API that you either cannot change or don’t want to upgrade just now, you may convert it like this:
Date accessExpiryDate = getFromLegacyApi();
LocalDate ld = accessExpiryDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
The rest is as before. And now you’ve embarked on using the modern API and can migrate your code base in this direction at your own pace.
Link: Oracle tutorial: Date Time explaining how to use java.time.
Since you have specified the date format as yyyy-MM-dd, it is formatted as that. Just fix your date format to the expected formatting.
e.g: d MMM yyyy
As already suggested by #JonSkeet, you should read the API documentation.
Anyway, the format should be in your case d MMM yyyy.

Changing LocalDateTimeFormat to include seconds and milliseconds

As per the requirement, my code is supposed to append date from a ZonedDateTime parameter, and Time from OffSetTime parameter into this format, "yyyy-MM-dd HH:mm:ss.SSSz". However, i was not been able to achieve this
I have tried various ways , including the one below, using DateTimeFormatter.
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2019-05-23T09:00:00-05:00");
OffsetTime offsetTime = OffsetTime.parse("08:59:00-05:00");
LocalDateTime localDateTime = LocalDateTime.of(zonedDateTime.toLocalDate(), offsetTime.toLocalTime());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSz");
String finalDate = localDateTime.format(formatter);
I notice that :
- code is throwing "java.time.DateTimeException: Unable to extract value: class java.time.LocalDateTime" at localDateTime.format(formatter)
The expectation is to get the DateTime in String like so - "2019-05-23T08:59:00.000Z"
Any help appreciated, Thank you for your time.
Four issues:
LocalDateTime doesn't have any time zone information, so don't use it.
Even if it did, your inputs only have a time zone offset, not a full time zone, so you format string cannot use z, as that requires a time zone name. Use XXX instead.
Since the inputs are offset -05:00 you shouldn't expect output with Z (Zulu), as that means +00:00, unless you also expect the time to be adjusted by 5 hours.
The format pattern for year should use uuuu, not yyyy. See uuuu versus yyyy in DateTimeFormatter formatting pattern codes in Java?
Assuming you want to keep the time zone, change code to:
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2019-05-23T09:00:00-05:00");
OffsetTime offsetTime = OffsetTime.parse("08:59:00-05:00");
OffsetDateTime offsetDateTime = zonedDateTime.toLocalDate().atTime(offsetTime);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSXXX");
System.out.println(offsetDateTime.format(formatter));
2019-05-23 08:59:00.000-05:00
If you instead want Zulu time, i.e. UTC, with the time adjusted, add the line to make the adjustment:
OffsetDateTime offsetDateTime = zonedDateTime.toLocalDate().atTime(offsetTime)
.withOffsetSameInstant(ZoneOffset.UTC);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSXXX");
System.out.println(offsetDateTime.format(formatter));
2019-05-23 13:59:00.000Z

String of format 2018-11-26T15:12:03.000-0800 to java.time.localdatetime of format "M/dd/yy HH:mm:ss a z" conversion throwing exception

i wrote an util function to convert a string time value of format 2018-11-26T15:12:03.000-0800 to localdatetime of format "M/dd/yy HH:mm:ss a z"
string of format 2018-11-26T15:12:03.000-0800 to java.time.localdatetime of format "M/dd/yy HH:mm:ss a z" conversion throwing exception.
public static LocalDateTime convertStringToTime(String time){
String pattern = "M/dd/yy HH:mm z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
ZonedDateTime zonedDateTime = ZonedDateTime.parse(time,formatter);
return zonedDateTime.toLocalDateTime();
}
which gives me the below exception
java.time.format.DateTimeParseException: Text '2018-11-26T12:45:23.000-0800' could not be parsed at index 4
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
You say that you want: a LocalDateTime of format M/dd/yy HH:mm:ss a z. This is impossible for three reasons:
A LocalDateTime cannot have a format. Its toString method always returns a string like 2018-11-26T15:12:03 (ISO 8601 format), there is no way we can change that. You also shouldn’t want a LocalDateTime with a specific format; I include a link at the bottom explaining why not.
I assume that by z in your format you mean time zone abbreviation like PDT for Pacific Daylight Time. A LocalDateTime neither has UTC offset not time zone, so this doesn’t make sense.
Your input time string doesn’t hold any time zone either, only an offset from UTC. So to print a time zone abbreviation, you will first need to choose a time zone.
Instead I suggest:
ZoneId zone = ZoneId.of("America/Whitehorse");
DateTimeFormatter inputFormatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXX");
DateTimeFormatter desiredFormatter
= DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.LONG)
.withLocale(Locale.US);
String time = "2018-11-26T15:12:03.000-0800";
OffsetDateTime dateTime = OffsetDateTime.parse(time, inputFormatter);
String formattedDateTime = dateTime.atZoneSameInstant(zone)
.format(desiredFormatter);
System.out.println("Converted format: " + formattedDateTime);
Output is:
Converted format: 11/26/18, 3:12:03 PM PST
To convert date and time from a string in one format to a string in another format you generally need two DateTimeFormatters: one specifying the format of the string you’ve got and one specifying the format that you want.
Rather than building your own formatter from a format pattern string, rely on built-in formats when you can. In our case I specify FormatStyle.SHORT for the date (giving two-digit-year) and FormatStyle.LONG for the time, giving us the time zone abbreviation.
The idea of relying on built-in formats can be taken one step further. The string you’ve got is in ISO 8601 format, so we just need to piece two pieces together:
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendOffset("+HHmm", "Z")
.toFormatter();
It’s longer, but it’s less error-prone.
Links
Wikipedia article: ISO 8601.
My answer to want current date and time in “dd/MM/yyyy HH:mm:ss.SS” format explaining why you don’t want a date-time object with a format.

Java - SimpleDateFormat formatter to return epoch time with milliseconds [duplicate]

This question already has answers here:
Convert a date format in epoch
(6 answers)
Closed 5 years ago.
I am very new to Java and coding in general - I have some code which returns a timestamp in the following format yyyy.MM.dd HH:mm:ss:ms which is shown below:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");
This returns:
2017.07.19 11:42:30:423
Is there a way to edit the "SimpleDateFormat formatter" code above to return the date/time as an epoch timestamp that includes milliseconds so that the value returned is formatted as per the below?
1500464550423
I'm hoping that I can amend the ("yyyy.MM.dd HH:mm:ss:sss") part of the SimpleDateFormat formatter code to do this.
Any help or advice is much appreciated.
Thanks
You have a simple error in the use of case in your format pattern string (these are case sensitive). And worse, you are using the old and troublesome SimpleDateFormat class. One of the many problems with it is it’s not telling you what the problem is.
So I recommend you use the modern Java date and time API instead (I am deliberately using your format pattern string verbatim):
String receivedTimetamp = "2017.07.19 11:42:30:423";
DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:sss");
LocalDateTime dateTime = LocalDateTime.parse(receivedTimetamp, parseFormatter);
System.out.println(dateTime);
This code throws an IllegalArgumentException: Too many pattern letters: s. I hope this calls your awareness to the fact that you are using two s’s for seconds and three s’s for fraction of second. If it still isn’t clear, the documentation will tell you that lowercase s is correct for seconds, while you need uppercase S for the fraction. Let’s repair:
DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
Now the code prints 2017-07-19T11:42:30.423, so we have managed to parse the string correctly.
To convert to milliseconds we are still missing a crucial piece of information: in what time zone should the timestamp be interpreted? I think the two obvious guesses are UTC and your local time zone (which I don’t know). Try UTC:
System.out.println(dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli());
This produces 1500464550423, which is the number you asked for. I suppose we’re done.
If you wanted your JVM’s time zone setting instead, use .atZone(ZoneId.systemDefault()) instead of .atOffset(ZoneOffset.UTC), but beware that the setting may be altered by other software running in the same JVM, so this is fragile.
First of all, check the documentation of SimpleDateFormat. The pattern that corresponds to milliseconds is an uppercase S, while the lowercase s corresponds to seconds. The problem is that SimpleDateFormat usually doesn't complain and try to parse 423 as seconds, adding this amount to your end date (giving an incorrect result).
Anyway, SimpleDateFormat just parses a String to a java.util.Date or formats the Date to a String. If you want the epoch millis value, you must get it from the Date object:
// input string
String s = "2017.07.19 11:42:30:423";
// use correct format ('S' for milliseconds)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS");
// parse to a date
Date date = formatter.parse(s);
// get epoch millis
long millis = date.getTime();
System.out.println(millis); // 1500475350423
The problem is that SimpleDateFormat uses the system's default timezone, so the final value above (1500475350423) will be equivalent to the specificed date and time in my system's timezone (which can be different from yours - just for the record, my system's default timezone is America/Sao_Paulo). If you want to specify in what timezone this date is, you need to set in the formatter (before calling parse):
// set a timezone to the formatter (using UTC as example)
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
With this, the result for millis will be 1500464550423 (the equivalent to the specificed date and time in UTC).
To do the opposite (create a date from the millis value), you must create a Date object and then pass it to the formatter (also taking care of setting a timezone to the formatter):
// create date from millis
Date date = new Date(1500464550423L);
// use correct format ('S' for milliseconds)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// format date
String formatted = formatter.format(date);
Java new date/time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
As the input String has no timezone information (only date and time), first I parsed it to a LocalDateTime (a class that represents a date and time without timezone). Then I convert this date/time to a specific timezone and get the millis value from it:
// input string
String s = "2017.07.19 11:42:30:423";
// use correct format ('S' for milliseconds)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
// as the input string has no timezone information, parse it to a LocalDateTime
LocalDateTime dt = LocalDateTime.parse(s, formatter);
// convert the LocalDateTime to a timezone
ZonedDateTime zdt = dt.atZone(ZoneId.of("Europe/London"));
// get the millis value
long millis = zdt.toInstant().toEpochMilli(); // 1500460950423
The value is now 1500460950423, equivalent to the specified date and time in London timezone.
Note that the API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
You can also use ZoneOffset.UTC constant if you want to use UTC.
To do the opposite, you can get the millis value to create an Instant, convert it to a timezone and pass it to the formatter:
// create Instant from millis value
Instant instant = Instant.ofEpochMilli(1500460950423L);
// use correct format ('S' for milliseconds)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
// convert to timezone
ZonedDateTime z = instant.atZone(ZoneId.of("Europe/London"));
// format
String formatted = z.format(formatter);
First advice is to move to java8 java.time API instead of learning the broken java.date API
then do:
Instant i = Instant.now();
System.out.println(i.toEpochMilli());
in your case you can do:
LocalDateTime myldt = LocalDateTime.parse("2017-06-14 14:29:04",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(myldt.toInstant(ZoneOffset.UTC).toEpochMilli());
note that as soon as you play more with the api you will find more ways to achieve the same thing, at the end you will end invoking toEpochMilli
String strDate = "Jun 13 2003 23:11:52.454 UTC";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss.SSS zzz");
ZonedDateTime zdt = ZonedDateTime.parse(strDate,dtf);
System.out.println(zdt.toInstant().toEpochMilli()); // 1055545912454
You can try
long time = System.currentTimeMillis();
If you have a java.util.Date then invoking getTime() will return the number of millis since the epoch. For example:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");
Date dateToBeFormatted = new Date();
// this will print a datetime literal on the above format
System.out.println(formatter.format(dateToBeFormatted));
// this will print the number of millis since the Java epoch
System.out.println(dateToBeFormatted.getTime());
The key point here is that in order to get the number of millis since the epoch you do not need a SimpleDateFormatter because the number of millis since the epoch is a property of the Date.

Categories

Resources