Java SimpleDateFormat Timezone offset with minute separated by colon - java

How can I get my date formatted as 2012-11-25T23:50:56.193+01:00 using SimpleDateFormat?
If I use Z in the format like
yyyy-MM-dd'T'hh:mm:ss.SSSZ
then it shows
2013-03-06T11:49:05.490+0100

You can get the timezone offset formatted like +01:00 with the SimpleDateFormat in Java 7 (yyyy-MM-dd'T'HH:mm:ss.SSSXXX), or with the Joda's DateTimeFormat (yyyy-MM-dd'T'HH:mm:ss.SSSZZ).

Here’s the 2017 answer. If there is any way you can (which there is), throw the outdated classes like SimpleDateFormat overboard and use the modern and more convenient classes in java.time. In particular, the desired format, 2012-11-25T23:50:56.193+01:00 complies with ISO-8601 and therefore comes out of the box with the newer classes, just use OffsetDateTime.toString():
OffsetDateTime time = OffsetDateTime.now();
System.out.println(time.toString());
This prints something like
2017-05-10T16:14:20.407+02:00
One thing you may or may not want to be aware of, though, it prints as many groups of 3 decimals on the seconds as it takes to print the precision in the OffsetDateTime object. Apparently on my computer “now” comes with a precision of milliseconds (seconds with three decimals).
If you have an oldfashioned Date object, for example, you got it from a call to some legacy method, I recommend the first thing you do is convert it to Instant, which is one of the modern classes. From there you can easily other conversions depending on your requirements:
Date now = new Date();
OffsetDateTime time = now.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime();
System.out.println(time.toString());
I am really doing more conversions than necessary. atZone(ZoneId.systemDefault()) produced a ZonedDateTime, and its toString() will not always give you the format you said you wanted; but it can easily be formatted into it:
ZonedDateTime time = now.toInstant().atZone(ZoneId.systemDefault());
System.out.println(time.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

Related

Scala - How to convert LocalDateTime to ZonedDateTime formatted without GMT postfix?

I wanted to get the LocalDateTime in GMT so wrapped it with ZonedDateTime.
But gmtZoneTime is returned in the following format: 2019-10-29T00:00Z[GMT] While I need it to be: 2019-10-29T00:00:00.000+0000
How should I properly convert localDateTime into the GMT ZonedDateTime?
val currentDate:LocalDate = java.time.LocalDate.now
val localDateTime: LocalDateTime = currentDate.atStartOfDay
val gmtZoneTime: ZonedDateTime = localDateTime.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("GMT"))
You need to format the ZonedDateTime.
First approach would be to use predefined formatter like: java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME, however for GMT it shows 'Z' instead of '+0000' (default behaviour, other offsets are displayed like '+0100' etc.)
So the second one would be to create your own formatter like:
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")
and then use it to format ZonedDateTime like gmtZoneTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ"))
so you get a result like:
2019-10-28T23:00:00+0000
First your code is incorrect. When I ran it in my time zone (Europe/Copenhagen) just now, I got
2019-10-29T23:00Z[GMT]
I don’t think you intended 23:00 in GMT.
Second you may think of GMT or UTC as an offset (of zero from UTC), so it is more correct to use an OffsetDateTIme than a ZonedDateTime for the time. This also eliminates your unwanted suffix. In Java (it’s all I can write):
LocalDate currentDate = LocalDate.now(ZoneOffset.UTC);
OffsetDateTime gmtZoneTime = currentDate.atStartOfDay(ZoneOffset.UTC)
.toOffsetDateTime();
System.out.println(gmtZoneTime);
Output when running just now:
2019-10-30T00:00Z
Edit: You can safely regard UTC and GMT as synonymous since java.time does that (even though strictly speaking they may differ by up to a second).
I assumed you also wanted the date in UTC, so passed this as argument to LocalDate.now(). If you want the date in some other time zone, pass that time zone to LocalDate.now() so that it is clear from the code what you get.
If you want that specific format in your question, pezetem is correct in the other answer that you need to format into a string:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxx");
String formattedGmtTime = gmtZoneTime.format(formatter);
System.out.println(formattedGmtTime);
2019-10-30T00:00:00.000+0000
It seems wordy to me, though. I’d at least leave out the milliseconds since we know they are 0, probably the seconds too. Said without knowing your exact business case.
Link: Difference between UTC and GMT

Is there a simple way to change a timestamp value containing seconds and ms to a timestamp value having hours and minutes?

So I have an object ('Task') that has an attribute 'Start Date' which is basically a Timestamp object. So this date is in this format 'YYYY/MM/dd hh:mm:ss:ms'. But for a test case I am authoring, I need this date to be in this format 'YYYY/MM/dd hh:mm'. Also it needs to be a timestamp object as I have to set this value back to the 'Task' object.
I have tried several approaches including the snippet shown below:
SimpleDateFormat formatter = new SimpleDateFormat("YYYY-MM-dd hh:mm");
if (task.getStartDate() != null) {
String newDate = formatter.format(task.getStartDate());
Date date = formatter.parse(newDate);
task.setStartDate(new Timestamp(date.getTime()));
}
I expected the value of the timestamp to be in the format '2018-12-30 09:54' but it resulted in '2018-12-30 09:54:00.0'. So the questions that I have in mind is:
Is there a way to not consider the seconds and millis in the Timestamp object?
If no, then, is the snippet provided an efficient way to update the Timestamp object?
TL;DR
Avoid the Timestamp class if you can. It’s poorly designed and long outdated.
To answer your questions, no, a Timestamp hasn’t got, as in cannot have a format (the same holds true for its modern replacement, Instant (or LocalDateTime)).
Under all circumstances avoid SimpleDateFormat and Date. The former in particular is notoriously troublesome, and both are long outdated too.
Don’t put a format into your model class
You should not want an Instant nor a Timestamp with a specific format. Good practice in all but the simplest throw-away programs is to keep your user interface apart from your model and your business logic. The value of the Instant object belongs in your model, so keep your Instant or Timestamp there and never let the user see it directly. I hope that it’s clear to you that 2018-12-30 09:54 and 2018-12-30 09:54:00.0 represent the same value, the same Timestamp. Just like 17, 0017 and 0x11 represent the same integer value. When you adhere to what I said, it will never matter which format the Instant has got.
Whenever the user should see the date and time, this happens in the UI, not in the model. Format it into a String and show the string to the user. Similarly if you need a specific format for persistence or exchange with another system, format the Instant into a string for that purpose.
java.time and JDBC 4.2
Also for exchange with your database over JDBC, provided that you’ve got a JDBC 4.2 compliant driver, prefer to use a type from java.time over Timestamp. If the datatype on the database side is timestamp with time zone, very clearly recommended for a timestamp, pass an OffsetDateTime like
OffsetDateTime dateTime = yourInstant.atOffset(ZoneOffset.UTC);
yourPreparedStatement.setObject(4, dateTime);
Use setObject, not setTimestamp. Some drivers accept the Instant directly, without conversion to OffsetDateTime. If on the database side you need a mere timestamp (without time zone), use LocalDateTime in Java instead and pass one to setObject in the same way as above.
PS There are errors in your format pattern string
In a format pattern string, uppercase YYYY is for week based year and only useful with a week number. For year use either uuuu or lowercase yyyy. Similarly lowercase hh is for hour within AM or PM from 01 through 12 and only useful with an AM or PM marker. For hour of day from 00 through 23 you need uppercase HH. These errors will give you incorrect dates and times in most cases. Using the wrong case of format pattern letters is a very common mistake. SimpleDateFormat generally doesn’t mind, it just gives incorrect results. The modern DateTimeFormatter does a somewhat better job of notifying you of such errors.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Related questions
Formatting timestamp in Java about getting rid of the .0 decimal on the second of a Timestamp.
timestamp formatting in scala [duplicate] about getting a Timestamp with only date and hour (no minute, second or fraction of second).
java parsing string to date about uppercase Y for year in a format pattern string.
Comparing two times in android about lowercase h for hour of day in a format pattern string.

in java I need define date in this format 1999-05-31T13:20:00-05:00 [duplicate]

This question already has an answer here:
Java how to set 2011-11-06T14:34:16.679+02:00 into XMLGregorianCalendar
(1 answer)
Closed 5 years ago.
I need to define date in this format 1999-05-31T13:20:00-05:00
I am using below code
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD'T'hh:mm:ssZ");
sdf.setTimeZone(TimeZone.getTimeZone("EST"));
String date = sdf.format(new Date());
System.out.println(date);
but it is generating date in format 2017-04-117T08:28:46-0500 (missing semicolon in timezone)
After defining the date I have to create an instance of XMLGregorianCalendar with same date.
I was surprised you didn’t find the answer when searching for it. Anyway, it’s easy. Two words of caution first, though:
Skip the three-letter time zone abbreviations. Many are ambiguous. While I think EST only means Eastern Standard Time, this isn’t a full time zone, since (most of?) that zone is on EDT now, which does not make it very clear what result you want.
If there’s any way you can, skip the old-fashioned classes SimpleDateFormat, TimeZone and Date. The new classes in java.time are generally much nicer to work with.
The format you are asking for is exactly what DateTimeFormatter.ISO_OFFSET_DATE_TIME is giving you. If you meant to have the time formatted suitably for a user in the Eastern time zone, use:
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"))
.truncatedTo(ChronoUnit.SECONDS);
System.out.println(now.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
Note the use of the unambiguous time zone ID and of the mentioned formatter. The format will print milliseconds (and even smaller) if there are any, which you didn’t ask for. So I have cheated a bit: I am truncating the time to whole seconds. Now this prints something like:
2017-04-27T10:11:33-04:00
If instead you wanted the offset -05:00, that’s even easier:
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.ofHours(-5))
.truncatedTo(ChronoUnit.SECONDS);
System.out.println(now);
This prints something in the same format, but with the desired offset:
2017-04-27T09:11:33-05:00
The toString method of OffsetDateTime gives you the format you want. Of course, if you prefer, you can use the same formatter as before.
If truncating to seconds is a bit too much cheating for your taste, you may of course use a formatter without milliseconds:
DateTimeFormatter isoNoSeconds = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX");
System.out.println(now.format(isoNoSeconds));
This will work with both a ZonedDateTime and an OffsetDateTime, that is, with both of the above snippets.

Why does conversion between GregorianCalendar and OffsetDateTime fail when evaluating the ZoneInfo part?

I am converting an OffsetDateTime to a GregorianCalendar as part of populating values for an outbound web service. I just thought I'd test the actual conversion.
It is failing and i don't understand why - here is the test method:
#Test
public void testOffsetDateTimeToGregorianCalendar() {
// given the current gregorian utc time
GregorianCalendar expectedGregorianUtcNow = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
OffsetDateTime expectedUtcOffsetDateTime = OffsetDateTime.from(expectedGregorianUtcNow.toZonedDateTime());
// when converting to a GregorianCalendar
GregorianCalendar actualGregorianUtcNow = GregorianCalendar.from(expectedUtcOffsetDateTime.toZonedDateTime());
// then make sure we got the correct value
assertThat(actualGregorianUtcNow, equalTo(expectedGregorianUtcNow));
}
within the equalto, the comparison fails in the evaluation of the gregorianCutover. Why? Is this a bug?
it looks like actual has:
gregorianCutover = -9223372036854775808
and expected has:
gregorianCutover = -12219292800000
Everything else is correct as can be seen in the unit test output (gregorianCutover does not appear there):
java.lang.AssertionError:
Expected:<java.util.GregorianCalendar[time=1458667828375,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2016,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=4,DAY_OF_MONTH=22,DAY_OF_YEAR=82,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=30,SECOND=28,MILLISECOND=375,ZONE_OFFSET=0,DST_OFFSET=0]>
but: was <java.util.GregorianCalendar[time=1458667828375,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2016,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=4,DAY_OF_MONTH=22,DAY_OF_YEAR=82,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=30,SECOND=28,MILLISECOND=375,ZONE_OFFSET=0,DST_OFFSET=0]>
Did i do something wrong?
Basically, as far as I'm aware, java.time doesn't try to model a Gregorian cutover - so when an OffsetDateTime is converted back to a GregorianCalendar, that's done by modeling it as having a Gregorian calendar with a cutover back at the start of time. Hence the documentation for GregorianCalendar.from(ZoneDateTime):
Since ZonedDateTime does not support a Julian-Gregorian cutover date and uses ISO calendar system, the return GregorianCalendar is a pure Gregorian calendar and uses ISO 8601 standard for week definitions, which has MONDAY as the FirstDayOfWeek and 4 as the value of the MinimalDaysInFirstWeek.
Ideally, I'd suggest that you avoid using java.util.* in terms of date/time API... stick with java.time everywhere. But if you really need to, I'd probably suggest just not using GregorianCalendar.equals for testing equality - check the instant in time and the time zone separately, if those are the things you're interested in.

How to format a java.sql Timestamp for displaying?

How do I formate a java.sql Timestamp to my liking ? ( to a string, for display purposes)
java.sql.Timestamp extends java.util.Date. You can do:
String s = new SimpleDateFormat("MM/dd/yyyy").format(myTimestamp);
Or to also include time:
String s = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(myTimestamp);
Use String.format (or java.util.Formatter):
Timestamp timestamp = ...
String.format("%1$TD %1$TT", timestamp)
EDIT:
please see the documentation of Formatter to know what TD and TT means: click on java.util.Formatter
The first 'T' stands for:
't', 'T' date/time Prefix for date and time conversion characters.
and the character following that 'T':
'T' Time formatted for the 24-hour clock as "%tH:%tM:%tS".
'D' Date formatted as "%tm/%td/%ty".
If you're using MySQL and want the database itself to perform the conversion, use this:
DATE_FORMAT(date,format)
If you prefer to format using Java, use this:
java.text.SimpleDateFormat
SimpleDateFormat dateFormat = new SimpleDateFormat("M/dd/yyyy");
dateFormat.format( new Date() );
For this particular question, the standard suggestion of java.text.SimpleDateFormat works, but has the unfortunate side effect that SimpleDateFormat is not thread-safe and can be the source of particularly nasty problems since it'll corrupt your output in multi-threaded scenarios, and you won't get any exceptions!
I would strongly recommend looking at Joda for anything like this. Why ? It's a much richer and more intuitive time/date library for Java than the current library (and the basis of the up-and-coming new standard Java date/time library, so you'll be learning a soon-to-be-standard API).
Use a DateFormat. In an internationalized application, use the format provide by getInstance. If you want to explicitly control the format, create a new SimpleDateFormat yourself.
java.time
I am providing the modern answer. The Timestamp class is a hack on top of the already poorly designed java.util.Date class and is long outdated. I am assuming, though, that you are getting a Timestamp from a legacy API that you cannot afford to upgrade to java.time just now. When you do that, convert it to a modern Instant and do further processing from there.
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(Locale.GERMAN);
Timestamp oldfashionedTimestamp = new Timestamp(1_567_890_123_456L);
ZonedDateTime dateTime = oldfashionedTimestamp.toInstant()
.atZone(ZoneId.systemDefault());
String desiredFormat = dateTime.format(formatter);
System.out.println(desiredFormat);
Output in my time zone:
07.09.2019 23:02:03
Pick how long or short of a format you want by specifying FormatStyle.SHORT, .MEDIUM, .LONG or .FULL. Pick your own locale where I put Locale.GERMAN. And pick your desired time zone, for example ZoneId.of("Europe/Oslo"). A Timestamp is a point in time without time zone, so we need a time zone to be able to convert it into year, month, day, hour, minute, etc. If your Timestamp comes from a database value of type timestamp without time zone (generally not recommended, but unfortunately often seen), ZoneId.systemDefault() is likely to give you the correct result. Another and slightly simpler option in this case is instead to convert to a LocalDateTime using oldfashionedTimestamp.toLocalDateTime() and then format the LocalDateTime in the same way as I did with the ZonedDateTime.
String timeFrSSHStr = timeFrSSH.toString();

Categories

Resources