DateTimes in different formats is always a problem for me. I have a date with the datatype string like "2021-07-25"
I want to convert this date to the datatype LocalDateTime in the format 2021-07-25T00:00:00.000-05:00. I have the get and set property like below
private LocalDateTime relationshipStatusDate;
public LocalDateTime getRelationshipStatusDate() {
return relationshipStatusDate;
}
public void setRelationshipStatusDate(LocalDateTime relationshipStatusDate) {
this.relationshipStatusDate = relationshipStatusDate;
}
public void setRelationshipStatusDate(String time) {
if (time != null) {
try {
long epochTime = Long.parseLong(time);
this.relationshipStatusDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(epochTime), ZoneOffset.UTC);
} catch (NumberFormatException e){
this.relationshipStatusDate = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
}
}
}
and I am trying to format like below and its failing with an error "Unknown pattern letter T"
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-ddT00:00:00.000-05:00");
LocalDateTime dateTime = LocalDateTime.parse(statusDate, formatter);
Your format won't be parsable as it doesn't support default values like T00:00:00.000-05:00. You could escape literals e.g. use 'T00:00...' but that would just make the parser ignore them.
Instead, if all you get is a date then only parse a date and add the default time after that, e.g. like this:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
LocalDate date = LocalDate.parse(statusDate, formatter );
LocalDateTime dateTime = date.atStartOfDay(); //"relative" representation as the absolute instant would require adding a timezone
ZonedDateTime zonedDT = date.atSTartOfDay(ZoneOffset.UTC); //"absolute" representation of instant
I want to convert this date to the datatype LocalDateTime in the format 2021-07-25T00:00:00.000-05:00.
Note the potential misconception here: LocalDateTime does NOT have a format. It represents a date and time (from a local point of reference - not in absolute terms as the timezone is missing) and provides access to individual fields such as day of month, day of week etc. but it is not formatted. Formatting is applied when you convert that date object to a string.
tl;dr
LocalDate // Represent a date-only value, without a time-of-day and without a time zone or offset-from-UTC.
.parse( "2021-07-25" ) // Parse a string in standard ISO 8601 format to instantiate a `LocalDate` object.
.atStartOfDay( // Determine the first moment of the day on that date in that zone. NB: The day does *not* always begin at 00:00, so never assume that time.
ZoneId.of( "America/Bogota" ) // Real time zones have a name in Continent/Region format. Never use 2-4 letter pseudo-zones such as `CST` or `IST`.
) // Returns a `ZonedDateTime` object, a moment in the context of a time zone.
.toOffsetDateTime() // Strips away the time zone information, leaving only a date with time-of-day in a particular offset. Returns an `OffsetDateTime` object.
.toString() // Generate text in standard ISO 8601 format.
2021-07-25T00:00-05:00
Details
LocalDateTime is the wrong class
You said:
datatype LocalDateTime in the format 2021-07-25T00:00:00.000-05:00
That is a contradiction. The -05:00 at the end of your string is an offset-from-UTC. A LocalDateTime object has no offset.
You seem to misunderstand the purpose of LocalDateTime. That class does not represent a moment as seen through the wall-clock time with an offset-from-UTC used by the people of a particular region. For that purpose, use OffsetDateTime, or preferably, ZonedDateTime.
Use documentation rather than intuition when programming with unfamiliar classes. To quote the Javadoc for LocalDateTime:
A date-time without a time-zone … such as 2007-12-03T10:15:30.
…
This class does not store or represent a time-zone. Instead, it is a description of the date, as used for birthdays, … It cannot represent an instant on the time-line …
Here is my chart to summarize the types. Three classes represent a moment, while LocalDateTime does not.
You said:
I have a date with the datatype string like "2021-07-25"
So use LocalDate to represent that value.
By default, the java.time classes use standard ISO 8601 format when parsing/generating text. So no need to specify a formatting pattern here, as your input complies with that standard.
LocalDate ld = LocalDate.parse( "2021-07-25" ) ;
You said:
I want to convert this date to … the format 2021-07-25T00:00:00.000-05:00
Your example there uses only a mere offset rather than a time zone. I suggest you use a time zone whenever possible.
An offset is simply a number of hours-minutes-seconds, nothing more. A time zone is much more. A time zone is a history of the past, present, and future changes to the offset used by people of a particular region, as decided by their politicians.
ZoneId
So specify your time zone using Continent/Region naming.
ZoneId z = ZoneId.of( "America/Cancun" );
ZonedDateTime
Let java.time determine the first moment of the day on that date as seen in that time zone. Be aware that the day does not always start at 00:00. So never hard-code that time-of-day; let java.time do the work here.
ZonedDateTime zdt = ld.atStartOfDay( z ); // Determine the first moment of the day as seen in that zone. Not always 00:00.
Generate text to represent the value inside our ZonedDateTime. The ZonedDateTime#toString method generates text in a format that wisely extends the ISO 8601 format by appending the name of the time zone in square brackets.
String output = zdt.toString();
2021-07-25T00:00-05:00[America/Cancun]
Pull all that code together.
LocalDate ld = LocalDate.parse( "2021-07-25" );
ZoneId z = ZoneId.of( "America/Cancun" );
ZonedDateTime zdt = ld.atStartOfDay( z ); // Determine the first moment of the day as seen in that zone. Not always 00:00.
String output = zdt.toString();
See this code run live at IdeOne.com.
2021-07-25T00:00-05:00[America/Cancun]
OffsetDateTime
If you insist on generating text in your stated format, while omitting the name of the time zone, use OffsetDateTime.
String output = zdt.toOffSetDateTime().toString() ;
All of these topics have been covered many times on Stack Overflow. Search to learn more.
Related
Hi I want to convert String value 2020-12-16T19:20:30+01:00 UTC to either LocalDateTime or ZonedDateTime in java
I tried solution:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-DDThh:mm:ssTZD", Locale.ENGLISH);
final String responseTimeStamp = "2020-12-16T19:20:30+01:00 UTC";
ZonedDateTime zdt = ZonedDateTime.parse(responseTimeStamp, dtf);
Which gives me the error
Exception in thread "main" java.lang.IllegalArgumentException: Unknown pattern letter: T at java.base/java.time.format.DateTimeFormatterBuilder.parsePattern(DateTimeFormatterBuilder.java:1815) at java.base/java.time.format.DateTimeFormatterBuilder.appendPattern(DateTimeFormatterBuilder.java:1712) at java.base/java.time.format.DateTimeFormatter.ofPattern(DateTimeFormatter.java:588) at learning/learning.SpringDemo.main(SpringDemo.java:21)
tl;dr
OffsetDateTime
.parse(
"2020-12-16T19:20:30+01:00 UTC"
.replace( " UTC" , "" )
)
.withZoneSameInstant(
ZoneId.of( "America/Edmonton" )
)
ISO 8601
Your input string:
2020-12-16T19:20:30+01:00 UTC
… nearly complies with the ISO 8601 standard for data-exchange date-time formats. To fully comply, delete the SPACE and UTC from the end. The +01:00 at the end means “one hour ahead of UTC", so the UTC at the end is redundant.
String input = "2020-12-16T19:20:30+01:00 UTC".replace( " UTC" , "" ) ;
Offset versus time zone
Parse as an OffsetDateTime because your input indicates small offset from UTC, not a time zone.
An offset is merely a number of hours-minutes-seconds ahead/behind the prime meridian of UTC. A time zone is much more. A time zone is a history of the past, present, and future changes to the offset used by the people of a particular region as decided by their politicians. A time zone has a name in format of Continent/Region, such as Europe/Paris and Africa/Tunis.
OffsetDateTime
So the other Answer’s suggestion to use ZonedDateTime for parsing is misguided as no time zone is indicated. Your input has only an offset, therefore use OffsetDateTime.
No need to specify a formatting pattern. Our modified input complies with ISO 8601, and the java.time classes use those standard formats by default when parsing/generating strings.
OffsetDateTime odt = OffsetDateTime.parse( input ) ;
LocalDateTime
You asked how to get a LocalDateTime. That class lacks any concept of offset or time zone. So beware, if you convert from OffsetDateTime, you are discarding valuable information.
So while I don’t recommend doing this, here is the code.
LocalDateTime ldt = odt.toLocalDateTime() ;
ZonedDateTime
You asked how to adjust into a time zone.
To adjust from our offset to a time zone, merely specify the desired time zone.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = odt.withZoneSameInstant( z ) ;
There are a few things wrong with your code. I suggest you to take a look at the DateTimeFormatter documentation.
YYYY -> This means week-based-year, you can have a look here to see the difference between year-of-era. So you should be using yyyy.
DD -> This means day-of-year, so December 16 is equal to 350. In your case you want to use dd, day-of-month.
T -> There isn't a pattern for T, so you can put it like a text to formmat you date 'T'
TZD -> I don't know what you are trying to use here and I couldn't find the patter +03:00 UTC, you can try to use O
So your final pattern should be "yyyy-MM-dd'T'HH:mm:ssO". It doens't work for UTC and I couldn't find it on ZoneId list, maybe because UTC is +00:00 already, so UTC+01:00 is equal to +01:00.
After a lot of working understanding the pattern, I found out that you are looking for ISO_ZONED_DATE_TIME, so you could just change your code like below:
DateTimeFormatter dtf = DateTimeFormatter.ISO_ZONED_DATE_TIME;
final String responseTimeStamp = "2020-12-16T19:20:30+01:00";
ZonedDateTime zdt = ZonedDateTime.parse(responseTimeStamp, dtf);
I'm creating a string out from current time and I wanted to convert it to timestamp again, but the thing is, that it's subtracts 2 hours while converting.
This is the steps I'm doing -
DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder().append(DateTimeFormatter.ofPattern("uuuu-MM-dd")).appendLiteral(" ")
.append(DateTimeFormatter.ofPattern("HH:mm:ss")).parseLenient();
long ts = Clock.systemUTC().millis();
System.out.println(ts);
Instant instant = Instant.ofEpochMilli(ts);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
String str = zonedDateTime.format(dateTimeFormatterBuilder.toFormatter());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
long timestamp = simpleDateFormat.parse(str).getTime();
System.out.println(timestamp);
} catch (ParseException e) {
e.printStackTrace();
}
output -
1639065502667
1639058302000
(2021-12-09 15:58:22
2021-12-09 13:58:22)
why is the diff of the 2 hours?
how can I parse it so that the outputs will be equal?
tl;dr
Trying to understand Date, Calendar, and SimpleDateFormat is a huge waste of time. Use only their replacements, the java.time classes.
LocalDateTime // Represent a date with time-of-day, but lacking the context of a time zone or offset-from-UTC. So *not* a moment, *not* a point on the timeline.
.parse( // Parse your text string input into a date-time object.
"2021-12-09 15:58:22" // Your input of date with time-of-day but no offset/zone.
.replace( " " , "T" ) // Replace SPACE with a `T` to comply with standard ISO 8601 format.
) // Returns a `LocalDateTime` object.
.atZone( // Place that date-with-time into the context a particular time zone.
ZoneId.of( "America/Montreal" ) // Specify a time zone by its `Continent/Region` name.
) // Returns a `ZonedDateTime` object, a date with time-of-day as seen through the wall-clock time used by the people of a particular region. This *does* represent a moment, *is* a specific point on the timeline.
.toInstant() // Adjust from time zone to UTC (an offset of zero hours-minutes-seconds). This represents the very same moment as the `ZonedDateTime` object above, but as seen through a different wall-clock time.
.toEpochMilli() // Get a count of milliseconds from first moment of 1970 in UTC (1970-01-01T00:00Z) to the moment of our `Instant` object (& `ZonedDateTime` object).
See this code run live at IdeOne.com. There you can click fork to make a copy, alter, and run.
1639083502000
Avoid legacy date-time classes
Regarding your specific question about a two hour difference, the obvious cause would be a time zone difference.
Parsing incomplete information
Your parsing, SimpleDateFormat("yyyy-MM-dd HH:mm:ss") is something of a wild card. The result will be a java.util.Date object, which represents a moment, a date with time-of-day as seen with an offset of zero. But your input lacks an indicator of offset or zone. As commented by Sotirios Delimanolis, you are parsing with partial input, with incomplete information.
So some default zone/offset will be applied. I do not know what zone or offset in particular, because I do not care. That terrible class is tragically flawed, and should be avoided.
Also, yet another problem with the Date class is that its toString method has the anti-feature of applying the JVM’s current default time zone to adjust away from the UTC value represented by that class. Very confusing, as this creates the illusion of that zone being a part of Date object but it is not. As I said, a terrible class, tragically flawed.
Use only java.time classes instead.
java.time
Understand that a date with time-of-day is inherently ambiguous, is not a moment.
If you are tracking 4 PM on the 9th, we do not know if that means 4 PM in Tokyo Japan, 4 PM in Toulouse France, or 4 PM in Toledo Ohio US — three very different moments that happen several hours apart.
LocalDateTime ldt = LocalDateTime.parse( "2021-12-09 16:00:00" ) ;
To track a moment, a point on the timeline, you must place ne date-with-time in the context of an offset from UTC or of a time zone.
An offset is merely a number of hours-minutes-seconds ahead or behind the baseline of modern timekeeping, the prime meridian at Royal Observatory, Greenwich.
A time zone is much more. A time zone is a named history of the past, present, and future changes to the offset used by the people of a particular region. Each zone has a name in format of Continent/Region such as Europe/Berlin or Asia/Tokyo.
To track moments as seen in UTC, with an offset of zero, use Instant.
Instant instant = Instant.now() ;
To see that same moment through the wall-clock time used by people in a region, apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Edmonton" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
As for your use of SimpleDateFormat, Date, and Calendar, don’t. Avoid these legacy date-time classes. Hey were designed by people who did not understand date-time handling. They were supplanted years ago by the modern java.time classes defined in JSR 310. Sun, Oracle, and the JCP community all gave up on those classes. I suggest you do the same.
In your code:
long ts = Clock.systemUTC().millis();
Instant instant = Instant.ofEpochMilli(ts);
That is the same as doing this:
Instant.now().truncatedTo( ChronoUnit.MILLISECONDS )
In your code:
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
(A) When working with mere offsets rather than time zones, use OffsetDateTime class. The ZonedDateTime class is for working with time zones.
(B) A briefer way to adjust from Instant to a zoned moment was shown above:
myInstant.atZone( z )
The answer was only setting the timezone to UTC -
DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder().append(DateTimeFormatter.ofPattern("uuuu-MM-dd")).appendLiteral(" ")
.append(DateTimeFormatter.ofPattern("HH:mm:ss")).parseLenient();
long ts = Clock.systemUTC().millis();
System.out.println(ts);
Instant instant = Instant.ofEpochMilli(ts);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
String str = zonedDateTime.format(dateTimeFormatterBuilder.toFormatter());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
*******
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
*******
long timestamp = simpleDateFormat.parse(str).getTime();
System.out.println(timestamp);
} catch (ParseException e) {
e.printStackTrace();
}
The dateTimeFomatter builder uses format without milliseconds and without timezone.
That's why the str value contain no information about them.
Then simpleDateFormat.parse(str) uses timezone of JVM which is UTC+02:00 in this case.
Trace what is going on:
Instant instant = Instant.now();
// => 2021-12-09 15:58:22.798 +00:00
String str = zonedDateTime.format(dateTimeFormatterBuilder.toFormatter());
// => "2021-12-09 15:58:22"
simpleDateFormat.parse(str);
// => 2021-12-09 15:58:22.000 +02:00
You just need to fix the pattern (add millis .SSS and timezone XXX parts) to make the results consistent as expected:
DateTimeFormatter.ofPattern("HH:mm:ss.SSSXXX")
// and something similar for SimpleDateFormat if needed
Parsing Instant from a custom formatted string.
This example shows how to parse Instant from serialized time assuming that there is a fixed timezone for all cases.
var serializedDateTime = "2020-01-01 10:20:30";
var zoneId = ZoneOffset.UTC; // may be any other zone
var format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
var instant = LocalDateTime
.parse(serializedDateTime, format)
// LocalDateTime is unzoned, just representation of (date + time) numbers in a single object
.atZone(zoneId)
// apply a zone to get ZonedDateTime (point in space-time on Earth)
.toInstant();
// convert to Instant (the same point adjusted to UTC+00:00)
Let me guess, your timezone is UTC+2?
simpleDateFormat.parse(str) assume that your date in current system timezone, but it is in UTC.
I am trying to truncate milliseconds from a UTC time zone.
I have the code below where I am able to remove milliseconds but I still get the Z at the end.
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC );
OffsetDateTime eventDateTime=now.minus(4, ChronoUnit.MINUTES);
System.out.println("====Event date Time before truncate===");
System.out.println(eventDateTime);
System.out.println("====Event date Time after truncate===");
System.out.println(eventDateTime.truncatedTo(ChronoUnit.SECONDS));
This outputs the following:
====Event date Time before truncate===
2021-03-09T20:46:24.081Z
====Event date Time after truncate===
2021-03-09T20:46:24Z
tl;dr
To represent a moment in UTC, use Instant class rather than LocalDateTime or OffsetDateTime.
Instant
.now() // Returns a `Instant` representing the current moment including a fractional second.
.truncatedTo(
ChronoUnit.SECONDS // Granularity of what you want chopped off. In this case, we lop off any fractional second.
) // Returns another `Instant` object. Per immutable objects, a new object is instantiated rather than altering ("mutating") the original.
.minus( // Go backwards on the timeline.
Duration.ofMinutes( 4 ) // Amount of time to go backwards.
) // Returns another `Instant` object.
.toString() // Generate text in standard ISO 8601 format, with `Z` on the end meaning an offset of zero hours-minutes-seconds from the UTC temporal prime meridian.
Zulu time
The Z at the end represents vital information: the date-time represents a moment as seen with an offset from UTC of zero hours-minutes-seconds. This letter is defined as part of the standard formats in ISO 8601. The letter is pronounced “Zulu” per aviation/military tradition.
If you do not care about offset or time zone in your problem domain, then you are using the wrong type.
The types Instant, OffsetDateTime, and ZonedDateTime all represent a moment, a specific point on the timeline. All three involve an offset or time zone.
LocalDateTime
If you want only a date with time-of-day but lacking the context of an offset/zone, then use LocalDateTime. No Z will appear in text representing the value of a LocalDateTime because no offset is involved.
Just be aware that a LocalDateTime object is inherently ambiguous, and does not represent a moment. In other words, calling LocalDateTime.now is almost never the right thing to do. But if you insist:
LocalDateTime ldt = LocalDateTime.now( ZoneOffset.UTC ) ;
The Z is the timezone information. You can convert the OffsetDateTime instance to a LocalDateTime like this:
eventDateTime.truncatedTo(ChronoUnit.SECONDS).toLocalDateTime()
There can be two ways:
Preferred way: Use DateTimeFormatter
Use OffsetDateTime#toLocalDateTime: The problem with this approach is that the output string is automatically truncated to minutes if the seconds part is zero.
Demo:
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtfWithoutSecFraction = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss");
DateTimeFormatter dtfWithSecFraction = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSSSS");
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
OffsetDateTime eventDateTime = now.minusMinutes(4);
System.out.println("====Event date Time before truncate===");
System.out.println(eventDateTime);
System.out.println(eventDateTime.toLocalDateTime());
System.out.println(dtfWithSecFraction.format(eventDateTime));
System.out.println("====Event date Time after truncate===");
System.out.println(eventDateTime.truncatedTo(ChronoUnit.SECONDS));
System.out.println(eventDateTime.truncatedTo(ChronoUnit.SECONDS).toLocalDateTime());
System.out.println(dtfWithoutSecFraction.format(eventDateTime.truncatedTo(ChronoUnit.SECONDS)));
}
}
Output:
====Event date Time before truncate===
2021-03-09T21:17:17.589016Z
2021-03-09T21:17:17.589016
2021-03-09T21:17:17.589016
====Event date Time after truncate===
2021-03-09T21:17:17Z
2021-03-09T21:17:17
2021-03-09T21:17:17
Note that Z stands for Zulu which specifies date-time in UTC (i.e. a timezone offset of +00:00 hours).
The following table gives you an overview of java.time types:
As you can see, OffsetDateTime, ZonedDateTime etc. carry timezone information and you can get just the date-time part using the techniques mentioned in the solution above.
Learn more about the modern date-time API from Trail: Date Time.
Currently my method is able to parse and format date and time with an offset.
While I experienced with JUnit I discovered -for many people pretty obvious- mistake that I'm only able to parse it if it contains an offset.
I either get
Unable to obtain OffsetDateTime from TemporalAccessor or I can't parse time with an offset.
This is my code so far:
Working input:
"2020-01-12T10:30-06:00"
Not working input:
"2020-01-12T10:30"
OffsetDateTime offsetDateTime = OffsetDateTime.parse(date, buildIso8601Formatter());
Instant instant = offsetDateTime.toInstant();
return LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
It works fine for datetimes with an offset but not the other way around.
In the end I want to be able to parse a datetime with/without an offset in the same method.
Moment
Working input: "2020-01-12T10:30-06:00"
Not working input: "2020-01-12T10:30"
These inputs are two very different animals. The first represents a moment, the second does not. The first determines a specific point on the timeline, the second does not.
The second lacks the crucial context of a time zone or offset-from-UTC. So we do not know if the second input represents 10:30 in the 12th in Tokyo Japan, or 10:30 in Tunis Tunisia, or 10:30 in Toledo Ohio US – all very different moments, several hours apart.
Faulty data source
If you have a source of inputs that arbitrarily omits the offset/zone info, then you don’t have a problem with your own Java programming, your data source has a problem.
Imagine a data source that provided a series of monetary amounts, some amounts indicating the currency of Canadian dollars, euros, or Japanese yen, while some amounts arbitrarily omitted any indication of currency. Obviously that would be considered faulty data that should be fixed at the source.
If you really want to work with this faulty data, simply look for the presence of a Plus or Minus sign. If found, parse as a OffsetDateTime. If omitted, parse as a LocalDateTime.
if( input.contains( "+" ) || input.contains( "-" ) ) {
OffsetDateTime odt = OffsetDateTime.parse( input ) ;
} else {
LocalDateTime ldt = LocalDateTime.parse( input ) ;
}
Alternatively, try to parse as one type. If DateTimeParseException thrown, try the other type.
If you are certain the input missing its offset was intended for a particular zone or offset, apply that offset or zone.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
If you want to lose the time zone while keeping the offset-from-UTC, to match your other OffsetDateTime objects, call toOffsetDateTime.
OffsetDateTime odt = zdt.toOffsetDateTime() ;
FYI, the difference between time zone and mere offset… An offset is just a number of hours-minutes-seconds ahead of (positive) or behind (negative) UTC, the prime meridian. A time zone is much more. A time zone is a history of the past, present, and future changes to the offset used by the people of a particular region, as set (and often changed!) by their politicians.
You can parse a String that has an offset to an OffsetDateTime directly, but you cannot to that with a String that doesn't have information about the offset or a time zone.
Do it somehow like shown here:
public static void main(String[] args) {
String working = "2020-01-12T10:30-06:00";
String notWorking = "2020-01-12T10:30";
// directly parse the String with an offset to an OffsetDateTime
OffsetDateTime offsetDateTime = OffsetDateTime.parse(working,
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
// parse the String without an offset to a LocalDateTime first
LocalDateTime localDateTime = LocalDateTime.parse(notWorking,
DateTimeFormatter.ISO_LOCAL_DATE_TIME);
// print them just to see the results
System.out.println(offsetDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
System.out.println(localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
// then convert the LocalDateTime to an OffsetDateTime by adding a ZoneOffset to it
OffsetDateTime fromLocalDateTime = localDateTime.atOffset(ZoneOffset.of("-06:00"));
// and print that
System.out.println(fromLocalDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}
The resulting output is
2020-01-12T10:30:00-06:00
2020-01-12T10:30:00
2020-01-12T10:30:00-06:00
When trying to convert from String to Local Date, an error is occurred and date cant be parsed
I am trying to convert a date which is in String format (eg: 2019-11-11T19:12:59.598) to Local Date (eg: 2019-11-11) format.
String dateInString = "2019-11-11T19:12:59.598";
public LocalDateTime DateToYear(String dateInString) {
Instant instant = Instant.parse(dateInString);
System.out.println("Instant : " + instant);
//get date time only
LocalDateTime result = LocalDateTime.ofInstant(instant, ZoneId.of(ZoneOffset.UTC.getId()));
//get localdate
System.out.println("LocalDate : " + result.toLocalDate());
return result;
}
One of my test method is calling this method DateToYear(String dateInString).
ISO 8601
Your input string complies with the ISO 8601 standard for textual date-time values.
The java.time classes use the standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
LocalDateTime
Your input string lacks an indicator of time zone or offset-from-UTC.
So we must parse as a LocalDateTime.
String dateInString = "2019-11-11T19:12:59.598";
LocalDateTime ldt = LocalDateTime.parse( input ) ;
Not a moment
Your input string does not represent a moment, is not a point on the timeline. Without the context of a time zone or offset, we do not know if you meant 7 PM on November 11 this year in Tokyo Japan, or 7 PM in Tunis Tunisia, or 7 PM in Toledo Ohio. These are all different moments, happening several hours earlier/later than one another. All we know is this string meant 7 PM on that date somewhere, but we know not where — so we know not when precisely.
To simply extract the date-only portion from your LocalDateTime, call toLocalDate.
LocalDate ld = ldt.toLocalDate() ;
Because your input is not a moment, your line:
Instant instant = Instant.parse(dateInString);
…makes no sense. An Instant represents a moment in UTC, a specific point on the timeline. But your string is not necessarily intended for UTC; we simply do not know what offset/zone was intended. We cannot tell that by looking at just the string.
If you happen to know for certain that input string was meant for UTC:
Educate the people who published that data about the importance of zone/offset. If they meant UTC, they should have appended a +00:00 or the abbreviation Z (pronounced “Zulu”).
Apply the constant ZoneOffset.UTC to get a OffsetDateTime which represents a moment as seen in a particular offset-from-UTC.
Code:
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ; // Making a moment of ambiguous input. Do this only if you are *certain* of the zone/offset intended by the publisher of this data input.
Get the date for that moment as seen in that offset.
LocalDate localDate = odt.toLocalDate() ;
If you know for certain the input string was meant for a particular time zone, apply a ZoneId to get a ZonedDateTime object. Then extract a LocalDate.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
LocalDate localDate = zdt.toLocalDate() ;
Keep in mind that for any given moment the date varies around the globe by time zone. So the LocalDate here may represent a different date than seen in the input string, being a day ahead or behind the date of the input string.
It will parse if you put a Z at the end of your string. See DateTimeFormatter.ISO_INSTANT
jshell> Instant.parse("2019-11-11T19:12:59.598")
| java.time.format.DateTimeParseException thrown: Text '2019-11-11T19:12:59.598' could not be parsed at index 23
| at DateTimeFormatter.parseResolved0 (DateTimeFormatter.java:2046)
| at DateTimeFormatter.parse (DateTimeFormatter.java:1948)
| at Instant.parse (Instant.java:395)
| at (#10:1)
jshell> Instant.parse("2019-11-11T19:12:59.598Z")
==> 2019-11-11T19:12:59.598Z