SimpleDateFormat parse 2018-11-08_21h34m46sZ - java

Hi want to convert UTC times to local time and i am doing this
public class TimeZoneN {
public static void main( String[] args ) throws ParseException {
String timeStr1 = "2018-11-08_21h34m46sZ";
String formatStr1 = "yyyy-MM-dd_HH'h'mm'm'ss's'Z";
SimpleDateFormat formatter = new SimpleDateFormat( formatStr1 );
formatter.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
Date date1 = formatter.parse( timeStr1 );
System.out.println( date1 );
}
}
i am getting a parse exception because od the Z, but when i do
String formatStr1 = "yyyy-MM-dd_HH'h'mm'm'ss'sZ'";
It passes, is that valid though ? Woudn't that consider sZ as a single constant and not Z as the timezone token ?

You are correct that Z denotes Zulu time, another name for UTC. You may also think of it as offset zero from UTC. So you will want to parse Z as an offset to ensure that your time is interpreted correctly.
java.time
However, don’t use SimpleDateFormat. It’s notoriously troublesome and long outdated. Don’t use Date either, it too is long outdated and it too has design problems.
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd_H'h'm'm's's'X");
String timeStr1 = "2018-11-08_21h34m46sZ";
Instant instant1 = formatter.parse(timeStr1, Instant::from);
System.out.println(instant1);
Output:
2018-11-08T21:34:46Z
For the sake of completeness:
want to convert … to local time
Taking America/Toronto as a random example:
ZonedDateTime dateTime = instant1.atZone(ZoneId.of("America/Toronto"));
System.out.println(dateTime);
Output:
2018-11-08T16:34:46-05:00[America/Toronto]
In a comment you asked about Z:
what difference would that make if i dont include it at all ?
Two things:
You want to make sure the string includes the required offset and object if not, or you risk that errors pass unnoticed. It’s called input validation.
As I mentioned you want to parse Z as an offset or you cannot extract an unambiguous point in time from the parsed values.
Link: Oracle tutorial: Date Time explaining how to use java.time.

Related

Converting one date time format into another in Java

I have a situation where I need to convert one Java date time format into another but have been having just a bear of a time doing so. Been searching for solutions a long time and have tried many things that have just not worked but I'm at my wits end :(.
I have to convert from
yyyy-MM-dd'T'HH:mm:ss
to
MM/dd/yyyy HH:mm:ss
This is the last thing I've tried, but alas it has no effect at all at transforming the pattern:
private Instant convertInstantFormat(Instant incomingDate) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(AUTH_DATE_PATTERN)
.withZone(ZoneId.systemDefault());
return Instant.parse(formatter.format(incomingDate));
}
Where
AUTH_DATE_PATTERN = "MM/dd/yyyy HH:mm:ss";
incomingDate = 2021-10-22T06:39:13Z
and outgoing date = 2021-10-22T06:39:13Z
I'm sure this is probably just the most naive attempt.
I've tried standardizing the date format and then reformatting, but no go.
I'm just sort of out of steam.
As always, any and all help from this incredible community is tremendously appreciated!
UPDATE
I just wanted to point out that the input and output to this method are of type "Instant."
Apologies for not making this clear initially.
I have to convert from yyyy-MM-dd'T'HH:mm:ss to MM/dd/yyyy HH:mm:ss
Your incoming date time format is ISO_LOCAL_DATE_TIME.
String datetime = "2021-12-16T16:22:34";
LocalDateTime source = LocalDateTime.parse(datetime,DateTimeFormatter.ISO_LOCAL_DATE_TIME);
// desired output format
String AUTH_DATE_PATTERN = "MM/dd/yyyy HH:mm:ss";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(AUTH_DATE_PATTERN);
String output = source.format(formatter);
System.out.println(output);
prints
12/16/2021 16:22:34
If your incoming date is 2021-10-22T06:39:13Z that is a zoned date time and can be parsed-from/formatted-to using
DateTimeFormatter.ISO_ZONED_DATE_TIME.
tl;dr
Instant // Represents a point on the time line.
.parse( "2021-10-22T06:39:13Z" ) // Returns an `Instant` object. By default, parses text in standard ISO 8601 for at where `Z` means offset of zero.
.atOffset( ZoneOffset.UTC ) // Returns an `OffsetDateTime` object.
.format(
DateTimeFormatter.ofPattern( "MM/dd/uuuu HH:mm:ss" )
) // Returns a `String` object.
See this code run live at IdeOne.com.
10/22/2021 06:39:13
Details
You said:
incomingDate = 2021-10-22T06:39:13Z
Your formatting pattern fails to match your input string.
Your input string happens to comply with the ISO 8691 format used by default in Instant.parse. So no need to specify a formatting pattern.
Instant instant = Instant.parse( "2021-10-22T06:39:13Z" ) ;
The Z on the end means an offset of zero hours-minutes-seconds from the prime meridian of UTC.
You asked to generate text representing that moment in the format of MM/dd/yyyy HH:mm:ss. I recommend including an indicator of the offset or time zone. But it you insist on omitting that, read on.
Convert from the basic class Instant to the more flexible OffsetDateTime class.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
Specify your formatting pattern.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu HH:mm:ss" ) ;
Generate your desired text.
String output = odt.format( f ) ;
To learn more, search Stack Overflow. These topics have already been addressed many times.
Append timezone 'z' info at the end of the format pattern otherwise parsing throws an exception.
Here's a working example.
Unit Test (Passing)
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class DateFormatConverterTest {
#Test
void convertDate() {
final String incomingDate = "2021-10-22T06:39:13Z";
final String expectedOutgoingDate = "2021/10/22T06:39:13Z";
String actualOutgoingDate = new DateFormatConverter().convertDate(incomingDate);
assertThat(actualOutgoingDate).isEqualTo(expectedOutgoingDate);
}
}
Implementation
import java.time.format.DateTimeFormatter;
public class DateFormatConverter {
private static final DateTimeFormatter INCOMING_DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssz");
private static final DateTimeFormatter OUTGOING_DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy/MM/dd'T'HH:mm:ssz");
String convertDate(String incoming) {
return OUTGOING_DATE_TIME_FORMAT.format(INCOMING_DATE_TIME_FORMAT.parse(incoming));
}
}

Convert YYYY-MM-DDThh:mm:ssTZD format date string to local time

In my spring boot application I have to convert ISO 8601 datetime to localdatetime without using JODA. Currently what I am doing is
String receivedDateTime = "2019-11-13T00:11:08+05:00";
ZonedDateTime zonedDateTime = ZonedDateTime.parse(receivedDateTime);
DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = new Date();
try {
date = utcFormat.parse(zonedDateTime.toString());
} catch (ParseException e) {
e.printStackTrace();
}
When I am using receivedDateTime with +00:00 like "2019-11-13T00:11:08+00:00" then it does not give any parsing error but not converting either. When I use +01:00 at the end then it also gives the parsing error.
UPDATE: 1
As per #Deadpool answer, I am using it like
String receivedDateTime = "2019-11-13T00:11:08+05:00";
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "0000").optionalEnd()
.toFormatter();
OffsetDateTime dt = OffsetDateTime.parse(receivedDateTime, formatter);
LocalDateTime ldt = dt.toLocalDateTime();
System.out.println(ldt);
and the the value of ldt it print is 2019-11-13T00:11:08.
UPDATE 2:
I tried using C# the same example and it gives me this date time {2019-11-12 11:11:08 AM}, which looks correct as the input time GMT +5 Hours and local time is EST America. So, when it converted it then it went back to 12th of Nov. Here is the code
var timeString = "2019-11-13T00:11:08+05:00";
DateTime d2 = DateTime.Parse(timeString, null, System.Globalization.DateTimeStyles.RoundtripKind);
Console.WriteLine("Hello World!" + d2);
UPDATE 3: So it boils down to following solution input String "2019-11-13T06:01:41+00:00" and output is local date "2019-11-13T00:01:41" Where system defauld ZoneId is "America/Chicago" which is -06:00 GMT
private LocalDateTime convertUtcStringToLocalDateTime(String UtcDateTime) {
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "0000").optionalEnd()
.toFormatter();
OffsetDateTime dateTime = OffsetDateTime.parse(UtcDateTime, formatter);
return dateTime.atZoneSameInstant(ZoneId.of(ZoneId.systemDefault().getId())).toLocalDateTime();
}
Using java.time alone this is simpler than you seem to think:
String receivedDateTime = "2019-11-13T00:11:08+05:00";
OffsetDateTime parsedDateTime = OffsetDateTime.parse(receivedDateTime);
ZonedDateTime dateTimeInMyTimeZone
= parsedDateTime.atZoneSameInstant(ZoneId.systemDefault());
System.out.println(dateTimeInMyTimeZone);
When I ran this in America/Toronto time zone, the output was:
2019-11-12T14:11:08-05:00[America/Toronto]
Since your string contains an offset, +05:00, and no time zone, like Asia/Karachi, use an OffsetDateTime for parsing it. Then convert to your local time zone using the atZoneSameInstant method. Even though you asked for your local time, don’t be fooled into using LocalDateTime. That class represent a date and time without any time zone, which is not what you need (and seldom needed at all).
Fortunately it’s easy to avoid the old classes SimpleDateFormat, DateFormat, TimeZone and Date. They were always poorly designed, the first two in particular are notoriously troublesome. They are all long outdated now. Instead get all the functionality we dream of from java.time, the modern Java date and time API.
What happened in your code?
Don’t use 'Z' in a format pattern string (and I repeat, don’t use SimpleDateFormat).
No matter if you use ZonedDateTime or OffsetDateTime, when you use toString with offset zero (as parsed from +00:00), the offset is printed as Z, which matches the 'Z' in your format pattern string, so your second parsing works. Only parsing once, converting back to string and parsing again is needlessly complicated. Worse when the original offset was +01:00 or +05:00. These are rendered the same again from toString, so don’t match 'Z', which caused your ParseException. Never use 'Z' in a format pattern string. Z denotes an offset of zero and needs to be parsed as an offset for you to get the correct result.
By using DateTimeFormatter you can customize the date format with different offset format by making them optional
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "0000").optionalEnd()
.toFormatter();
And the use the OffsetDateTime to parse string representing with offset
A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00.
OffsetDateTime dateTime = OffsetDateTime.parse("2019-11-13T00:11:08+0000", formatter);
OffsetDateTime dateTime = OffsetDateTime.parse("2019-11-13T00:11:08+05:00", formatter);
If you want to convert it into local time zone time LocalDateTime then use atZoneWithSameInstant()
LocalDateTime local = dateTime.atZoneSameInstant(ZoneId.of("America/New_York")).toLocalDateTime()
Note : Don't use SimpleDateFormat and util.Date which are legacy old framework

Java - Error when serializing/deserializing the date

I'm having trouble to figure out what is this date format: 2019-02-28T12:17:46.279+0000. I have tried different date formats to get this result but nothing worked. Closest pattern was: yyyy-MM-dd'T'HH:mm:ss.SSSZ But with this pattern output was like this: 2019-02-28T12:17:46.279-0000 (- is after seconds instead of +)
I get this exception:
Caused by: java.lang.IllegalArgumentException: 2019-02-28T12:17:46.279+0000
at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl$Parser.skip(XMLGregorianCalendarImpl.java:2932)
at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl$Parser.parse(XMLGregorianCalendarImpl.java:2898)
at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl.<init>(XMLGregorianCalendarImpl.java:478)
at org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl.newXMLGregorianCalendar(DatatypeFactoryImpl.java:230)
at __redirected.__DatatypeFactory.newXMLGregorianCalendar(__DatatypeFactory.java:132)
at javax.xml.bind.DatatypeConverterImpl.parseDate(DatatypeConverterImpl.java:519)
at javax.xml.bind.DatatypeConverter.parseDate(DatatypeConverter.java:431)
at eu.europa.ec.my.custom.package.model.mapper.XsdDateTimeConverter.unmarshal(XsdDateTimeConverter.java:23)
My XsdDateTimeConverter class looks like this:
public class XsdDateTimeConverter {
public static Date unmarshal(String dateTime) {
return DatatypeConverter.parseDate(dateTime).getTime();
}
public static String marshalDate(Date date) {
final Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return DatatypeConverter.printDate(calendar);
}
public static String marshalDateTime(Date dateTime) {
final Calendar calendar = Calendar.getInstance();
calendar.setTime(dateTime);
return DatatypeConverter.printDateTime(calendar);
}
}
And parsed date in my postgres db looks like this:
move_timestamp timestamp(6) with time zone
2019-02-28 12:17:46.279+00
In my rest method I use ObjectMapper like this.
MyCustomResponseDto responseDto = customService.getCustomResponseDto(query);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
String strValue = mapper.writeValueAsString(responseDto);
return Response.ok(strValue).build();
I guess what I really wanted is what is the right pattern for this date. I can go in this page: http://www.sdfonlinetester.info/ and enter my pattern (e.g. yyyy-MM-dd'T'HH:mm:ss.SSSZ) and it gives you an actual date output for that pattern. I need the other way around. I want to enter my date and it will give me the right pattern for it.
tl;dr
OffsetDateTime.parse(
"2019-02-28T12:17:46.279+0000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" , Locale.ROOT )
)
java.time
You are using terrible Calendar class that was supplanted years ago by the java.time classes.
ISO 8601
Your input string is in standard ISO 8601 format, designed for human-readable machine-parseable textual representations of date-time values. That is a good thing.
The java.time classes use ISO 8601 formats by default when parsing/generating strings.
OffsetDateTime
You should be able to simply parse with OffsetDateTime.
OffsetDateTime.parse( "2019-02-28T12:17:46.279+0000" )
…but unfortunately the optional COLON character being omitted from the offset (+00:00) is a problem. The OffsetDateTime class has a minor bug where it refuses to parse without that character. The bug is discussed here and here.
The ISO 8601 standard permits the colon’s absence, but practically you should always include it. The OffsetDateTime class is not alone; I have seen other libraries that break when the colon or padding zeros are absent. I suggest asking the publisher of your data to use the full ISO 8601 format including the colon.
The workaround for the OffsetDateTime bug is to define a DateTimeFormatter explicitly.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" , Locale.ROOT ) ;
Then parse.
String input = "2019-02-28T12:17:46.279+0000" ;
OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;
To generate text in full standard ISO 8601 format, simply call toString.
String output = odt.toString() ;
See this code run live at IdeOne.com.
output: 2019-02-28T12:17:46.279Z
The Z on the end means UTC, that is +0000 or +00:00. Pronounced “Zulu”. Very commonly used, more immediately readable than the numeric offset.
If you want same output format as your input, use the same DateTimeFormatter.
String output = odt.format( f ) ;
You may try below code
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.ENGLISH);
String lastmod = format.format(new Date());
Save yourself a mountain of trouble and save the epochtime in millis. Only parse and render dates in UIs. Very very few cases of scheduling for humans require a computer to know hours, day, week, month, year... But saving an instant in time is just a 'long'.

Add minutes to timestamp

I need to add minutes into timestamp and return new value after that. Timestamp is taken from database and passed to method as String and has this pattern: yyyy-MM-dd hh:mm:ss.SSSSSS
public static String changeCreditTimeStampMin(String tmStmp, int minutesToAdd) {
tmStmp = tmStmp.substring(0, tmStmp.length() - 3);
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
java.util.Date parsedDate = dateFormat.parse(tmStmp);
java.sql.Timestamp timestamp = new java.sql.Timestamp(parsedDate.getTime() + minutesToAdd*60*1000);
tmStmp = timestamp.toString();
} catch (ParseException e) {
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
return tmStmp;
}
As you can see, my logic uses SimpleDateFormat and in order to use that I have to use substring operation on timestamp. My question, is there any better way I could get the same result without cutting the timestamp string? Please note that my java version is 1.5 and I cannot use newer versions.
The issue for you is that you are using mm. You should use MM. MM is for month and mm is for minutes. Try with yyyy-MM-dd HH:mm
Other approach:
static final long ONE_MINUTE_IN_MILLIS=60000;//millisecs
Calendar date = Calendar.getInstance();
long t=date.getTimeInMillis();
Date afterAddingTenMins=new Date(t + (10 *ONE_MINUTE_IN_MILLIS));
A better way?
Yes, use java.time classes rather than the old legacy date-time classes.
Change your string input to standard ISO 8601 format by replacing the space in middle with a T. I assume this string was intended to represent a moment in UTC. So, append a Z, short for Zulu, meaning UTC.
The java.time classes use ISO 8601 formats by default when parsing/generating string representations. So feed directly to the parse method without bothering to define a formatting pattern. An Instant represents a moment on the timeline in UTC with a result ion of nanoseconds.
Instant instant = Instant.parse( input );
Add minutes. If you want this in UTC, so you don't care about handling time zones and anomalies like Daylight Saving Time (DST), use this Instant to create another. Otherwise apply w time zone to get a ZonedDateTime.
long minutes = 5L;
Instant later = instant.plus( minutes , ChronoUnit.MINUTES );
Tip: Pass these Instant objects around your app rather than strings.

Convert date string to datetime object in Joda-Time?

I have a date string similar to:
"2014-04-10T00:00:00.000"
So I need to convert this to a Joda-Time DateTime object.
Here is my code :
String datePattern = "yyyy-MM-dd'T'HH:mm:ss.SSS";
DateTimeFormatter dateFormatter = DateTimeFormat.forPattern(datePattern);
currentCard.setStartDate("2014-04-10T00:00:00.000");
currentCard.setEndDate("2015-04-10T00:00:00.000");
DateTime startDateTime = dateFormatter.parseDateTime(currentCard.getStartDate());
DateTime endDateTime = dateFormatter.parseDateTime(currentCard.getEndDate());
if (startDateTime.isBeforeNow() && endDateTime.isAfterNow()) {
currentCard.setActive(true);
} else {
currentCard.setActive(false);
}
It tells me string is too short
I believe the correct syntax for the date pattern is "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'". That way the Z is literally used.
While the other answers are correct, both the answers and your question are working too hard.
ISO 8601 Format
The format of the string in question, "2014-04-10T00:00:00.000", is standard ISO 8601 format. The DateTime class in Joda-Time has a built-in ISO 8601 parser/formatter built-in, used by default. So no need to instantiate a formatter. Merely pass the string to the constructor of DateTime.
Time Zone
Specify a time zone by which to interpret that date-time value. Otherwise the JVM's current default time zone is applied.
Example:
DateTimeZone timeZoneMontréal = DateTimeZone.forID( "America/Montreal" );
Example Code
Some example code using Joda-Time 2.5.
DateTime dateTime = new DateTime( "2014-04-10T00:00:00.000", DateTimeZone.UTC );
If that string represented a wall-time† moment in Québec rather than UTC, then specify that time zone by which the string should be understood while parsing.
DateTime dateTime = new DateTime( "2014-04-10T00:00:00.000", timeZoneMontréal );
Specify Format
As per the comment by Meno Hochschild, you may prefer to specify the expected format of the incoming String. Joda-Time has many pre-defined formatters built-in, as well as permitting you to define your own. In this case, our string lacks a time zone offset at the end, so we specify the formatter known as dateHourMinuteSecondFraction.
What if the incoming string is malformed or using an unexpected format? An exception is thrown. For robust code, trap for that exception.
String input = "2014-04-10T00:00:00.000";
DateTimeZone timeZoneMontréal = DateTimeZone.forID( "America/Montreal" );
DateTimeFormatter formatter = ISODateTimeFormat.dateHourMinuteSecondFraction().withZone( timeZoneMontréal );
DateTime dateTime = null;
try {
dateTime = formatter.parseDateTime( input );
} catch ( IllegalArgumentException e ) {
System.out.println( "Unexpected format of incoming date-time string: " + input + ". Exception: " + e ); // Handle exception for bad input.
}
Adjust to UTC for comparison.
DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );
Dump to console.
System.out.println( "dateTime: " + dateTime );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
When run.
dateTime: 2014-04-10T00:00:00.000-04:00
dateTimeUtc: 2014-04-10T04:00:00.000Z
† Wall-Time = The time as usually seen on some clock on some wall in some locality.
Regarding your first edit using the pattern "yyyy-MM-dd'T'HH:mm:ss.SSSZ" and experiencing a parse problem with Z-input, it is obviously a version problem, see here:
On Joda-Time-release-notes for change 1.6 to 2.0 =>
"Allow 'Z' and 'ZZ' in format patterns to parse 'Z' as '+00:00' [2827359]"
So the solution is to use the newest version of Joda-Time. Note that the use of the pattern symbol Z is more powerful than just to use a literal 'Z' in pattern expression because any ISO-8601-compatible string might not only contain "Z" at the end but also offsets like "+0200". And if the offset might contain a colon (example "+05:30") then you should use the double ZZ in your pattern.
Comment about your edit to remove the pattern symbol Z:
In that case I do not see any exception with version 2.1. Joda-Time will just interprete the input as local time in system timezone and add the appropriate timezone offset. Anyway, you have to adapt your pattern to expected inputs, not otherwise around.

Categories

Resources