Parsing a Date and Time string into a ZonedDateTime object - java

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 ) ;

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.

Convert to ISO string with default values

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));
}
}

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.

How can i print the current date and time to an external text document?

I can get the date and time to print to the screen, but i cannot get it to print to the specified text document:
import java.sql.Timestamp;
import java.util.Date;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.io.FileWriter;
public class GetCurrentTimeStamp
{
public static void main( String[] args ) throws FileNotFoundException
{
PrintStream output = new PrintStream ("transaction-list.txt");
java.util.Date date= new java.util.Date();
System.out.print(date);
output.close();
}
}
try this:
output.print(date);
instead of System.out.print(date);
System.out.print() writes to the system console, not the file. You're creating a PrintStream but then writing the date output to the console. Try this:
PrintStream ps = new PrintStream("transaction-list.txt");
Date date = new Date();
ps.println(date.toString());
ps.close
Try this
PrintWriter output = new PrintWriter(new BufferedWriter(new FileWriter("transaction-list.txt", true))) // take away true, if you dont want it to append.
output.println(date);
tl;dr
Modern way to get current time in UTC:
String output = Instant.now().toString(); // In UTC, standard format.
or, zoned:
String output = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ).toString();
java.time
The other answers are correct, but use of java.util.Date is outmoded now by the java.time classes built into Java 8 and later.
The Instant class represents a moment on the timeline in UTC with a resolution up to nanoseconds.
Instant instant = Instant.now();
The standard ISO 8601 format used by toString may be all you need. The Z on the end is short for Zulu and means UTC.
String output = Instant.now().toString(); // 2011-12-03T10:15:30.728Z
Generally best to perform business logic and data exchange in UTC. But if expected by your user or data sink, you can can apply a time zone (ZoneId) to get a ZonedDateTime object. Specify a proper time zone name, never the 3-4 abbreviations like EST or IST seen in the media.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneID );
String output = zdt.toString(); // 2011-12-03T05:15:30.728-05:00[America/Montreal]
You can skip the Instant object as a shortcut.
ZonedDateTime zdt = ZonedDateTime.now( zoneId );
Toss it all together for a one-liner.
String output = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ).toString();
For other formats, search Stack Overflow for DateTimeFormatter.

Get minutes of date using Joda-Time

Following zulu date string is given:
2013-12-18T23:41:54.959Z
And I want to convert this to GMT and retrieve the minutes using Joda-Time. I build following method:
public static int minutesFromDateString(final String s){
DateTimeFormatter formatter = DateTimeFormat.forPattern("HH:mm").withZone(DateTimeZone.forID("Europe/Berlin"));
DateTime dt = formatter.parseDateTime(s);
Calendar calendar = Calendar.getInstance();
calendar.setTime(dt.toDate());
return calendar.get(Calendar.MINUTE);
}
However this returns an error:
12-22 16:04:11.940: E/AndroidRuntime(6433):
java.lang.IllegalArgumentException: Invalid format:
"2013-12-18T23:41:54.959Z" is malformed at "13-12-18T23:41:54.959Z"
Any ideas whats wrong?
You aren't using a valid pattern. Your pattern says it is looking for HH:mm, your real string is far more complex. Look at the DateTimeFormat docs. It looks like you want something like this: "yyyy-mm-dd'T'HH:mm:ss.SSS'Z'"
Just set proper pattern: "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
In your case:
public static int minutesFromDateString(final String s){
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(DateTimeZone.forID("Europe/Berlin"));
DateTime dt = formatter.parseDateTime(s);
Calendar calendar = Calendar.getInstance();
calendar.setTime(dt.toDate());
return calendar.get(Calendar.MINUTE);
}
Output:
41
See docs HERE
The answer by PearsonArtPhoto is correct. To add more…
Joda-Time
With Joda-Time, no need for format pattern, and no need for Calendar class. You are working too hard.
The DateTime class takes an ISO 8601 string directly in its constructor.
Call the getMinuteOfHour method on a DateTime to extract just that portion.
If you want UTC/GMT rather than a specific time zone, pass the built-in constant, DateTimeZone.UTC. Be aware that time zone could affect your minute-of-hour. Not all time zones adjust by full hours. India for example has an offset of five and a half hours ahead of UTC/GMT (+05:30).
String input = "2013-12-18T23:41:54.959Z";
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Berlin" ); // Or, DateTimeZone.UTC;
DateTime dateTime = new DateTime( input, timeZone );
int minuteOfHour = dateTime.getMinuteOfHour();
Dump to console…
System.out.println( "dateTime: " + dateTime );
System.out.println( "minuteOfHour: " + minuteOfHour );
When run…
dateTime: 2013-12-19T00:41:54.959+01:00
minuteOfHour: 41
java.time
Joda-Time has been officially replaced by the java.time framework built into Java 8 and later. While Joda-Time continues to be updated, future work will go into the java.time classes and their extension, ThreeTen-Extra project.
Much of java.time has been back-ported to Java 6 & 7 in the ThreeTen-Backport project. That work is adapted to Android in the ThreeTenABP project.
The discussion above applies to a java.time solution. An Instant is a moment on the timeline in UTC. Apply a time zone ZoneId to get a ZonedDateTime.
String input = "2013-12-18T23:41:54.959Z";
Instant instant = Instant.parse( input );
ZoneId zoneId = ZoneId.of( "Europe/Berlin" ); // Or, ZoneOffset.UTC;
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant, zoneId );
int minuteOfHour = zdt.getMinute(); // Gets the minute-of-hour field.

Categories