Convert to ISO string with default values - java

I want to convert string-presented date in custom format into ISO format.
The first step is pretty easy:
val parsed = DateTimeFormatter.ofPattern(pattern).parse(input)
Now I want to present this parsed value in ISO string, the problem is that input value can be
"13:35:23" with pattern "HH:mm:ss", and I want to be able to convert it to ISO as well, filling missed year/month/day etc with some default values, for example now(), so the resulting string will be for example 2020-07-09T13:35:23.000Z
Similar behaviour has toIsoString() method in JavaScript, if there are some ways to do that in Java?
P.S. Input can contain date/zone/ofset, so it is not only about parsing patterns like "HH:mm:ss"

tl;dr
Instead of thinking in terms of one elaborate formatting pattern for parsing, think in terms of combining parts.
Here we get the current moment as seen in UTC. Then we move to your desired time-of-day.
OffsetDateTime.now( ZoneOffset.UTC ).with( LocalTime.parse( "13:35:23" ) ).toInstant().toString()
Details
LocalTime
Parse your input appropriately.
LocalTime lt = LocalTime.parse( "13:35:23" ) ;
ZonedDateTime
Then combine with a date and time zone to determine a moment.
For any given moment, the date varies around the globe by time zone. So a time zone is crucial here.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.now( z ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
Instant
Adjust to UTC, an offset of zero hours-minutes-seconds, by extracting a Instant.
Instant instant = zdt.toInstant() ;
Generate your string output, in standard ISO 8691 format.
String output = instant.toString() ;
OffsetDateTime
If you want the date and your time input to be seen as being for UTC eprather than some other time zone, use ZoneOffset.UTC constant. Use OffsetDateTime rather than ZonedDateTime. Use with to use al alternate part, such as here where we substitute the current time-of-day part with your input time-of-day.
OffsetDateTime // Represent a moment as date,time, and offset -from-UTC (a number of hours-minutes-seconds).
.now( ZoneOffset.UTC ) // Capture current moment as seen in UTC.
.with(
LocalTime.parse( "13:35:23" )
)
.toInstant() // Extract the more basic `Instant` object, always in UTC by definition.
.toString() // Generate text representing the value of this date-time object. Use standard ISO 8601 format.

If you used LocalTime.parse instead of DateTimeFormatter.parse directly, you would get a "local time" object, which you can then add to a "local date" giving you a date time:
LocalTime time = LocalTime.parse(input, DateTimeFormatter.ofPattern(pattern));
LocalDateTime dateTime = LocalDate.now().atTime(time)
You can then format dateTime in whatever format you want.

Use DateTimeFormatterBuilder to provide defaults.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
class Main {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter =
// builder for formatters
new DateTimeFormatterBuilder()
// append both patterns inclosed by []
.appendPattern("[yyyy-MM-dd HH:mm:ss][HH:mm:ss]")
// provide defaults for year, month and day
.parseDefaulting(ChronoField.YEAR_OF_ERA, now.getYear())
.parseDefaulting(ChronoField.MONTH_OF_YEAR, now.getMonthValue())
.parseDefaulting(ChronoField.DAY_OF_MONTH, now.getDayOfMonth())
// build the formatter
.toFormatter();
String a = "13:35:23";
String b = "1234-01-01 13:35:23";
System.out.println(LocalDateTime.parse(a, formatter));
System.out.println(LocalDateTime.parse(b, formatter));
System.out.println(formatter.parse(a));
System.out.println(formatter.parse(b));
}
}

Related

Convert timestamp to Date time for a particular timezone

I want to convert a timestamp (which is in GMT) to a local date and time.
This is what I have implemented so far, but it is giving me wrong month
Timestamp stp = new Timestamp(1640812878000L);
Calendar convertTimestamp = convertTimeStamp(stp,"America/Phoenix");
System.out.println(convertTimestamp.getTime());
public static Calendar convertTimeStamp( Timestamp p_gmtTime, String p_timeZone) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy HH:MM:SS a", Locale.ENGLISH);
DateFormat formatter = DateFormat.getDateTimeInstance();
if (p_timeZone != null) {
formatter.setTimeZone(TimeZone.getTimeZone(p_timeZone));
} else {
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
}
String gmt_time = formatter.format(p_gmtTime);
Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(gmt_time));
return cal;
}
Any help would be appreciated.
You cannot convert a timestamp to another timezone, cause timestamps are always GMT, they are a given moment in the line of time in the universe.
We humans are used to local time on our planet, so a timestamp can be formatted to be more human readable, and in that context it is converted to a local timezone.
Using legacy java.util.* packages, this is done as follows:
DateFormat tzFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
tzFormat.setTimeZone(TimeZone.getTimeZone("CET")); // Use whatever timezone
System.out.println(tzFormat.format(date));
If you need to make "math" over the timestamp on local timezone (like, tomorrow at 8:00 local timezone), then the situation is more complex.
To do this you can resort to a number of hacks (like parsing or modifying the string obtained with the method above), or use the new Java date & time classes that have a specific class to deal with date and time in local time zones:
Instant timestamp = Instant.ofEpochMilli(inputValue);
ZonedDateTime romeTime = timestamp.atZone(ZoneId.of("Europe/Rome"));
Note how this second example uses "Europe/Rome" and not generically "CET". This is very important if you're planning to deal with timezones where DST is used, cause the DST change day (or if they use DST or not) may change from country to country even if they are in the same timezone.
tl;dr
Instant
.ofEpochMilli( // Parse a count of milliseconds since 1970-01-01T00:00Z.
1_640_812_878_000L
) // Returns a `Instant` object.
.atZone( // Adjust from UTC to a time zone. Same moment, same point on the timeline, different wall-clock time.
ZoneId.of( "America/Phoenix" )
) // Returns a `ZonedDateTime` object.
.format( // Generat text representing the date-time value kept within that `ZonedDateTime` object.
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.MEDIUM )
.withLocale( Locale.US )
) // Returns a `String` object.
See this code run live at IdeOne.com.
Dec 29, 2021, 2:21:18 PM
Details
You are using terrible old date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310. Never use Timestamp, Calendar, Date, SimpleDateFormat, etc.
Use the Instant class to represent a moment as seen in UTC, with an offset of zero hours-minutes-seconds.
long millisecondsSinceBeginningOf1970InUtc = 1_640_812_878_000L ;
Instant instant = Instant.ofEpochMilli( millisecondsSinceBeginningOf1970InUtc ) ;
Specify the time zone in which you are interested.
ZoneID z = ZoneId.of( "Africa/Tunis" ) ;
Adjust from offset of zero to that time zone to produce a ZonedDateTime object.
ZonedDateTime zdt = instant.atZone( z ) ;
Generate text representing that moment by automatically localizing. Use a Locale to specify the human language to use in translation as well as a culture to use in deciding abbreviation, capitalization, order of elements, and so on.
Locale locale = Locale.JAPAN ; // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ).withLocale( locale ) ;
String output = zdt.format( f ) ;
All of this has been addressed many times on Stack Overflow. Search to learn more.

Parsing a Date and Time string into a ZonedDateTime object

I am trying to parse a String with a date and time in a known time zone.
The strings have the following format:
2019-03-07 00:05:00-05:00
I have tried this:
package com.example.test;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Test {
public static void main( String[] args ) {
ZoneId myTimeZone = ZoneId.of("US/Eastern");
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ssXX");
ZonedDateTime zdt = ZonedDateTime.parse("2019-03-07 00:05:00-05:00", dateTimeFormatter.withZone(myTimeZone));
System.out.println(zdt);
}
}
This is the exception thrown:
Exception in thread "main" java.time.format.DateTimeParseException: Text '2019-03-07 00:05:00-05:00' could not be parsed at index 19
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
at java.time.ZonedDateTime.parse(ZonedDateTime.java:597)
at com.example.test.Test.main(Test.java:24)
C:\Users\user\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 0 seconds)
I am using Java 1.8.0_191.
Use this pattern: yyyy-MM-dd HH:mm:ssXXX
From the docs:
Offset X and x: ... Two letters outputs the hour and minute, without a
colon, such as '+0130'. Three letters outputs the hour and minute,
with a colon, such as '+01:30'.
So if your string contains a colon inside timezone, you should use 3 "X-es".
And capital Y means "week-based-year", not a regular one (y).
tl;dr
OffsetDateTime.parse(
"2019-03-07 00:05:00-05:00".replace( " " , "T" )
)
Use the offset, Luke
You do not need the time zone. Your string carries an offset-from-UTC of five hours behind UTC. That tells us a specific moment, a point on the timeline.
ISO 8601
Replace that SPACE in the middle of your input with a T to comply with ISO 8601. The java.time classes use the standard formats by default. So no need to specify a formatting pattern.
OffsetDateTime
Parse as an OffsetDateTime.
String input = "2019-03-07 00:05:00-05:00".replace( " " , "T" ) ;
OffsetDateTime odt = OffsetDateTime.parse( input ) ;
ZonedDateTime
If you know for certain this value was intended to a particular time zone, you can apply a ZoneId to get a ZonedDateTime.
Be aware that US/Eastern is deprecated as a time zone name. The modern approach is Continent/Region. Perhaps you mean America/New_York.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

Java 8 DateTimeFormatter

I need to replace SimpleDataFormat with Java 8 DateTimeFormatter. Below is the code with SimpleDateFormat.
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(source);
Now I need to change it to DateTimeFormatter. I tried as below
LocalDateTime ld = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Date startdate = dtf.parse(dtf);
Now this is generating exception.
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate localDate = LocalDate.parse("2017-02-11", dtf);
System.out.println(localDate.toString());
if you want Date object from LocalDate,the following works
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
As #JonSkeet advised, If you're using Java 8 you should probably avoid java.util.Date altogether
If looking for equivalent of your sdf in DateTimeFormatter try DateTimeFormatter.ISO_LOCAL_DATEExplore the DateTimeFormatter class for more formats.
LocalDateTime time = LocalDateTime.now();
time.format(DateTimeFormatter.ISO_LOCAL_DATE);
Use LocalDate instead of LocalDateTime if intrested in Date only.
tl;dr
java.util.Date.from(
LocalDate.parse( "2017-01-23" )
.atStartOfDay( ZoneId.of( "America/Montreal" ) )
.toInstant()
)
No need of formatting pattern
No formatting pattern needed. Your input string happens to be in standard ISO 8601 format. These standard formats are used by default in the java.time classes for parsing and generating strings.
LocalDate
Use LocalDate for a date-only value, without time-of-day and without time zone.
LocalDate ld = LocalDate.parse( "2017-01-23" );
ZonedDateTime
If you want a date-time, let java.time determine the first moment of the day. Do not assume that first moment is 00:00:00.
Determining first moment of the day requires a time zone. The date varies around the globe by zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ld.atStartOfDay( z );
If you want to perceive that moment through the lens of UTC, extract an Instant object.
Instant instant = zdt.toInstant();
The Instant is equivalent to the old legacy class java.util.Date. Both represent a moment on the timeline in UTC. The modern class has a finer resolution, nanoseconds rather than milliseconds.
Avoid java.util.Date
As others mentioned, you should stick with the modern java.time classes. But if you must, you can convert. Look to new methods added to the old classes.
java.util.Date d = java.util.Date.from( instant ) ;
One way of doing it would be -
LocalDateTime ld = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String date = ld.format(dtf);

How to apply timezone when formatting DateTime?

I have a datetime as 2011-01-11 01:51:10 and timezone as America/Los_Angeles
I want to get a localised date time for this value. This is what I do
val formatter1: DateTimeFormatter = DateTimeFormatter.ofPattern("y-M-d H:m:s");
val m1: LocalDateTime = LocalDateTime.parse("2011-01-11 01:51:10", formatter1);
println("DateTime: " + m1.atZone(ZoneId.of("America/Los_Angeles")))
The value that I get is
DateTime: 2011-01-11T01:51:10-08:00[America/Los_Angeles]
How do I convert it into localized datetime with -08:00 offset applied to it and no [America/Los_Angeles]?
You first have to specify which timezone that the time which you have parsed is in. Then specify an other one to convert into.
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("y-M-d H:m:s");
LocalDateTime m1 = LocalDateTime.parse("2011-01-11 01:51:10", formatter1);
ZonedDateTime z1 = m1.atZone(ZoneId.of("UTC"));
ZonedDateTime z2 = z1.withZoneSameInstant(ZoneId.of("America/Los_Angeles"));
System.out.println(z2.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
Looks like you are using java.time API which has a ZonedDateTime. You should probably use it instead of LocalDateTime, since that LocalDateTime does not have a time zone. From the docs:
A date without a time-zone in the ISO-8601 calendar system, such as 2007-12-03.
This class does not store or represent a time or time-zone. Instead, it is a description of the date, as used for birthdays. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
And then, ZonedDateTime docs states that:
A date-time with a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris.
This class handles conversion from the local time-line of LocalDateTime to the instant time-line of Instant. The difference between the two time-lines is the offset from UTC/Greenwich, represented by a ZoneOffset.
Using a ZonedDateTime, your code would be like:
import java.time._
import java.time.format._
val zoneId = ZoneId.of("America/Los_Angeles")
val formatter = DateTimeFormatter.ofPattern("y-M-d H:m:s").withZone(zoneId)
val zdt = ZonedDateTime.parse("2011-01-11 01:51:10", formatter)
The result you will see at the console will be:
zdt: java.time.ZonedDateTime = 2011-01-11T01:51:10-08:00[America/Los_Angeles]
That happens because you are using the default toString method of ZonedDateTime and looks like the DateTimeFormatter.ISO_OFFSET_DATE_TIME is exactly what you want. So your code should be:
import java.time._
import java.time.format._
val zoneId = ZoneId.of("America/Los_Angeles")
val formatter = DateTimeFormatter.ofPattern("y-M-d H:m:s").withZone(zoneId)
val zdt = ZonedDateTime.parse("2011-01-11 01:51:10", formatter)
val formatted: String = zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
Please look into my complete answer for this. Answer
String dateTime = "MM/dd/yyyy HH:mm:ss";
String date = "09/17/2017 20:53:31";
Integer gmtPSTOffset = -8;
ZoneOffset offset = ZoneOffset.ofHours(gmtPSTOffset);
// String to LocalDateTime
LocalDateTime ldt = LocalDateTime.parse(date, DateTimeFormatter.ofPattern(dateTime));
// Set the generated LocalDateTime's TimeZone. In this case I set it to UTC
ZonedDateTime ldtUTC = ldt.atZone(ZoneOffset.UTC);
System.out.println("UTC time with Timezone : "+ldtUTC);
// Convert above UTC to PST. You can pass ZoneOffset or ZoneId for 2nd parameter
LocalDateTime ldtPST = LocalDateTime.ofInstant(ldtUTC.toInstant(), offset);
System.out.println("PST time without offset : "+ldtPST);
// If you want UTC time with timezone
ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdtPST = ldtUTC.toLocalDateTime().atZone(zoneId);
System.out.println("PST time with Offset and TimeZone : "+zdtPST);
probably what you want is to get UTC time and then apply timezone offset to it.
It's quite easy to do with Joda time. For example:
DateTime.now().minus(timezoneOffset)
where timezoneOffset is int that will represent time shift at your location. Correct me if I'm wrong.

How to add user timezone to utc date

how to add user timezone to utc
i am getting utc date like this
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-ddHH:mm:ss");
DateTime dateTime = formatter.withOffsetParsed().parseDateTime(getval[2]);
DateTime dateTimeUtc = dateTime.toDateTime(DateTimeZone.UTC);
Now i want to get user Timezone and add it to utc to convert that to localtime
UPDATE
i was able to get the user timezone but could add it to the utc
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-ddHH:mm:ss");
DateTime dateTime = formatter.withOffsetParsed().parseDateTime(getval[2]);
java.util.Calendar now = java.util.Calendar.getInstance();
java.util.TimeZone timeZone = now.getTimeZone();
DateTimeZone dtZone = DateTimeZone.forID(timeZone.getID());
DateTime dateTimeUtc = dateTime.toDateTime(DateTimeZone.UTC);
ofm.setDate(dateTimeUtc.toDateTime(dtZone).toDate());
This below code may help you to get the time zone of the user
//get Calendar instance
Calendar now = Calendar.getInstance();
//get current TimeZone using getTimeZone method of Calendar class
TimeZone timeZone = now.getTimeZone();
//display current TimeZone using getDisplayName() method of TimeZone class
System.out.println("Current TimeZone is : " + timeZone.getDisplayName());
also the below link helps you to convert user's timezone to UTC
link
java.time
The Joda-Time project was succeeded by the java.time framework defined in JSR 310. Here is the modern solution using those new classes found in Java 8 and later.
Your input format is nearly compliant with the ISO 8601 standard. The data is just missing the T between the date portion and the time-of-day portion, and is missing a Z on the end to indicate UTC. See if you can educate the publisher of your data about this important standard.
String input = "2019-01-23T01:23:45.123456789Z" ;
The java.time classes use the standard formats by default. So no need to specify a formatting pattern.
Instant instant = Instant.parse( input ) ;
instant.toString() = 2019-01-23T01:23:45.123456789Z
If you can get the input format changed, define a formatting pattern to match.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-ddHH:mm:ss" ) ;
Lacking any indicator of time zone or offset, we must parse as a LocalDateTime. Note that such an object does not represent a moment, is not a specific point on the timeline.
String input = "2019-01-2301:23:45" ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
ldt.toString() = 2019-01-23T01:23:45
You claim to be sure this date and time were intended to represent a moment in UTC. So we can apply an offset using the constant ZoneOffset.UTC to produce a OffsetDateTime.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;
odt.toString() = 2019-01-23T01:23:45Z
Then you said you want to adjust this into a specific time zone. Same moment, same point on the timeline, but different wall-clock time.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
zdt.toString() = 2019-01-23T02:23:45+01:00[Africa/Tunis]
As you can see, Tunisia on that date was running an hour ahead of UTC. So the time-of-day appears to be 2 AM rather than 1 AM.
Here's a small example that gets the difference from a list of time zones (in hours):
import java.util.Date;
import java.util.TimeZone;
public class StackOverflowTimeZone {
public static void main(String[] a) {
Date date = new Date();
for(int index = 0; index < TimeZone.getAvailableIDs().length; index++) {
System.out.println(TimeZone.getAvailableIDs()[index] + " offset from UTC: " + TimeZone.getTimeZone(TimeZone.getAvailableIDs()[index]).getOffset(date.getTime()) / (60 * 60 * 1000) + " hours.");
}
}
}
The abstract class TimeZone was designed to get the offset of a designated time zone from Coordinated Universal Time (UTC). There is a list of time zones that can be found by using the method TimeZone.getAvailableIDs(). After getting the offset, you will need to do a few small calculuations in order to find out whether the designated time zone is ahead or behind UTC. The sign (+/-) of your output should correlate to whether that designated time zone is ahead or behind UTC.

Categories