I have a datetime string "2018-01-15 01:16:00" which is in EST timezone. I want to convert this into another timezone dynamically using the UTC offset. My javascript code passes this UTC offset as a parameter and the servlet has to convert/format this datetime string to the timezone identified by the provided offset.
I have tried many approaches including the one documented in the oracle tutorials but unable to arrive at a solution.
Below is my code that I am trying, any help is greatly appreciated.
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static final String DEFAULT_TIME_ZONE = ZoneId.SHORT_IDS.get("EST");
public static void main(String[] args) throws Exception {
String dateTime = "2018-01-15 02:35:00";
//parse the datetime using LocalDateTime
LocalDateTime defaultDateTime = LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(DATE_FORMAT));
//get the datetime in default timezone
ZoneId defaultZoneId = ZoneId.of(DEFAULT_TIME_ZONE);
ZonedDateTime defaultZoneDateTime = defaultDateTime.atZone(defaultZoneId);
System.out.println("EST time: "+defaultZoneDateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT)));
ZonedDateTime utcZonedDateTime = defaultZoneDateTime.withZoneSameInstant(ZoneId.of("UTC"));
String utcTime = defaultZoneDateTime.withZoneSameInstant(ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern(DATE_FORMAT));
System.out.println("UTC : "+utcTime);
//IST timezone
ZoneOffset offset = ZoneOffset.of("+05:30");
OffsetDateTime offsetDate = OffsetDateTime.of(utcZonedDateTime.toLocalDateTime(), offset);
String targetTimeZone = offsetDate.format(DateTimeFormatter.ofPattern(DATE_FORMAT));
System.out.printf("target time : "+targetTimeZone);
}
OUTPUT
EST time: 2018-01-15 02:35:00
UTC : 2018-01-15 07:37:00
target time : 2018-01-15 07:37:00
Expected target time : 2018-01-15 13:05:00
The immediate problem is this line:
OffsetDateTime offsetDate = OffsetDateTime.of(utcZonedDateTime.toLocalDateTime(), offset);
That's saying you want the same local date/time, but with the specified offset. That changes which instant in time is being represented.
Instead, you really want to represent the same instant in time, but at a particular offset. So the shortest fix is:
OffsetDateTime offsetDate = utcZonedDateTime.toInstant().atOffset(offset);
However, there are a number of other aspects which could do with changing:
Prefer ZoneOffset.UTC to ZoneId.of("UTC")
Using EST as a time zone is confusing - it's not clear whether you expect it to mean "Eastern Time" (changing between EST and EDT) or pure standard time of UTC-5. Assuming you actually mean "Eastern Time" it would be better to use America/New_York as a zone ID.
It's unclear what you want to happen if the input string represents a skipped or ambiguous value in Eastern time. These happen around DST transitions.
Next, you don't need to convert the ZonedDateTime in Eastern time into a ZonedDateTime in UTC at all. Either convert it directly to an instant:
OffsetDateTime target = defaultZoneDateTime.toInstant().at(offset);
Or create a ZonedDateTime for the target instead:
ZonedDateTime target = defaultZoneDateTime.withZoneSameInstant(offset);
Given that an offset isn't really a time zone, I'd probably go with the first of these.
You're using
OffsetDateTime.of(utcZonedDateTime.toLocalDateTime(), offset)
to create your target. You're thus constructing an OffsetDateTime in the target offset, having a LocalDateTime equal to the LocalDateTime in the UTC zone.
What you want is the exact same transformation as the one you're using to go from the EST time to UTC: keep the same instant, but go to a different timezone:
defaultZoneDateTime.withZoneSameInstant(offset);
or, if you really want an OffsetDateTime and not a ZonedDateTime:
OffsetDateTime.ofInstant(defaultZoneDateTime.toInstant(), offset);
Related
In Java,
If Instant represents a point in time, encoded as date and time in
UTC.
And LocalDateTime represents a point in time, encoded as date and time in the JVM local timezone.
Why then does LocalDateTime.ofInstant() require a ZoneId as a second argument ?
This makes LocalDateTime not only confusing and potentially incorrect, but also makes it identical to ZonedDateTime; because the timezone of LocalDateTime can be any timezone just like ZonedDateTime.
And LocalDateTime represents a point in time, encoded as date and time in the JVM local timezone.
No, that's not true. Regardless of the "encoded as" part (which I highly doubt, but which I don't have significant knowledge of to disprove), a LocalDateTime does not represent a point in time. It represents a local date/time, without reference to a specific time zone. Any given LocalDateTime occurs at different points in time in different time zones.
Currently the local date and time in the Europe/London time zone is 2023-01-26T08:50. The same point in time in (say) America/New_York would result in a different LocalDateTime. Whereas in America/New_York, the LocalDateTime of 2023-01-26T08:50 occurs as a different point in time.
For some LocalDateTime / time zone combinations, there may be zero or two corresponding points in time - for example, the LocalDateTime 2022-11-06T01:30 will occur in America/New_York at both 2022-11-06 05:30:00Z and 2022-11-06 06:30:00Z.
Hopefully this is sufficient evidence that a LocalDateTime really isn't a point in time...
A LocalDateTime represents a date and time without time zone information. It is used to represent "local time" (as an example for me, right now the local time is 2023-01-26 09:50). An Instant is always at UTC (example, the time right now is 2023-01-26 08:50 UTC). To transform between an Instant and what the observer considers to be local time, you need to know the ZoneId of the location of the observer (e.g. for me Europe/Amsterdam), otherwise you cannot derive a local time.
And to be clear, a LocalDateTime does not represent a point in time (that is what Instant is for). To expand my example, for me the local time 2023-01-26 09:50 is now past, while for Jon Skeet (in Europe/London), that local time will happen in slightly less than an hour).
.ofInstant() is there to specify the instant and timezone.
If you don't want to specify the time zone and instant you can use .now() wich will use the local date and time.
If you want to specify the instant but not the ZoneId you can use ZomeId.systemDefault().
An Instant is independent from time zones or offsets, but a LocalDateTime is not. Although it does not have a ZoneId or ZoneOffset, it's values are partially based on the offset the specific zone currently has.
Here's a code example with different zones that lead to different values of the very same Instant:
public static void main(String[] args) throws DateTimeParseException {
// example instant (see output)
var instant = Instant.now();
// get the instant with different time zones
var ldtBerlin = LocalDateTime.ofInstant(instant, ZoneId.of("Europe/Berlin"));
var ldtCanberra = LocalDateTime.ofInstant(instant, ZoneId.of("Australia/Canberra"));
var ldtKolkata = LocalDateTime.ofInstant(instant, ZoneId.of("Asia/Kolkata"));
var ldtLA = LocalDateTime.ofInstant(instant, ZoneId.of("America/Los_Angeles"));
// print all the results
System.out.println("Instant " + instant.toEpochMilli() + " in different zones:");
System.out.println(ldtBerlin + " (Berlin)");
System.out.println(ldtCanberra + " (Canberra)");
System.out.println(ldtKolkata + " (Kolkata)");
System.out.println(ldtLA + " (Los Angeles)");
}
Output:
Instant 1674724841016 in different zones:
2023-01-26T10:20:41.016228 (Berlin)
2023-01-26T20:20:41.016228 (Canberra)
2023-01-26T14:50:41.016228 (Kolkata)
2023-01-26T01:20:41.016228 (Los Angeles)
View the different values, those are the local dates and times of the zones, but a LocalDateTime does not have any! You can use other objects, like ZonedDateTime (has zone and offset) and OffsetDateTime (has offset). Both of them have a method toLocalDateTime(), in case you need a LocalDateTime later on…
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.
So I have been looking up on how to properly parse an incoming datetime, problem is that this string contains the zone as well which apparently can't be parsed for some reason.
To give an example of the incoming date time string:
2021-10-05T10:00:00.0000000
Now I tried to the following:
var dateTimeString = "2021-10-05T10:00:00.0000000"
var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
var date = LocalDate.parse(dateTimeString, formatter)
I tried replacing Z with nothing and with ZZZZ, but that didn't work I assume it doesn't work because of the plus or minus sign not being present. FYI, I receive the date in this format because of the Microsoft Graph API when retrieving the calendar events.
Any idea as to how this date should be formatted properly?
Edit: This comes from Microsoft Graph. Basically they give like a date as an object:
"start": {
"dateTime": "2021-10-05T10:00:00.0000000",
"timeZone": "UTC"
}
This is the page of the documentation that explains this date object: dateTimeTimeZone resource type.
Update:
I was finally able to solve this date issue, what I did was the following:
var inputDateTime = "2021-10-05T10:00:00.0000000"
var inputTimeZone = "UTC"
var zonedDateTime = ZonedDateTime.parse(
inputDateTime,
DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.of(inputTimeZone))
).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime()
This way, the date would be converted correctly to the right time zone and to the right Date/Time.
As I can see from docs you've provided https://learn.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0
dateTime String A single point of time in a combined date and time representation ({date}T{time}; for example, 2017-08-29T04:00:00.0000000).
timeZone String Represents a time zone, for example, "Pacific Standard Time". See below for more possible values.
dateTime object has no zone encoded. And all 7 zeroes represent fractions of a second. In such case it's regular ISO_DATE_TIME and you don't need to create your own formatter.
The following code should work
var dateTimeString = "2021-10-05T10:00:00.0000000"
var date = LocalDate.parse(dateTimeString, DateTimeFormatter.ISO_DATE_TIME)
Your Date-Time string does not have timezone information
Your Date-Time string, 2021-10-05T10:00:00.0000000 does not have timezone information. The .0000000 represents the fraction of a second and as of now, java.time is capable of handling up to 9 digits of precision (i.e. nanosecond of precision).
Since it does not have timezone information, it represents a local Date-Time and hence should be parsed into LocalDateTime.
You do not need a DateTimeFormatter for your Date-Time string
The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards. Your Date-Time string is already in the ISO 8601 format.
Demo:
import java.time.LocalDateTime;
public class Main {
public static void main(String args[]) {
var dateTimeString = "2021-10-05T10:00:00.0000000";
var ldt = LocalDateTime.parse(dateTimeString);
System.out.println(ldt);
}
}
Output:
2021-10-05T10:00
ONLINE DEMO
How to get ZonedDateTime out of the LocalDateTime instance?
You can use LocalDateTime#atZone to convert attach a ZoneId to a LocalDateTime resulting into a ZonedDateTime.
ZonedDateTime zdt = ldt.atZone(ZoneId.of("Etc/UTC"));
Note: If you need an Instant, you can get it from this instant of ZonedDateTime e.g.
Instant instant = zdt.toInstant();
An Instant represents an instantaneous point on the timeline, normally represented in UTC time. The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Learn more about the modern Date-Time API* from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time.
For the case that the last 4 digits in your example String are not representing a time zone:
Parse it without a formatter (no need since it would be perfect ISO standard if the last 4 digits are just additional fractions of second), but also consider the time zone you get with the JSON:
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
fun main() {
// the time String from JSON
var dateTimeString = "2021-10-05T10:00:00.0000000"
// the zone from JSON (may not always work, but does with UTC)
var timeZone = "UTC"
// create the zone from the timezone String
var zoneId = ZoneId.of(timeZone)
// then parse the time String using plain LocalDateTime and add the zone afterwards
var zdt: ZonedDateTime = LocalDateTime.parse(dateTimeString).atZone(zoneId)
// print some results
println("Full ZonedDateTime: ${zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)}")
println("(Local)Date only: ${zdt.toLocalDate()}")
}
Full ZonedDateTime: 2021-10-05T10:00:00Z[UTC]
(Local)Date only: 2021-10-05
Please note that parsing the time zones currently supported by Windows won't work this easy (except from UTC), but the time zones supported by the calendar API are (mostly) sufficient for the creation of a java.time.ZoneId.
As a supplement: Your documentation mentions Pacific Standard Time as a time zone string that may come as part of your MS Graph dateTimeTimeZone. I don’t think the other answers can handle that one, so I should like to show how you do handle it in Java.
private static final DateTimeFormatter ZONE_FORMATTER
= DateTimeFormatter.ofPattern("zzzz", Locale.ENGLISH);
static ZoneId parseZone(String timeZoneString) {
try {
return ZoneId.from(ZONE_FORMATTER.parse(timeZoneString));
} catch (DateTimeParseException dtpe) {
return ZoneId.of(timeZoneString);
}
}
I believe that this handles the strings mentioned in the documentation and also UTC from your question. I am demonstrating just three different ones:
String[] msTimeZoneStrings = { "UTC", "Pacific Standard Time", "Pacific/Honolulu" };
for (String zoneString : msTimeZoneStrings) {
ZoneId zid = parseZone(zoneString);
System.out.format("%-21s parsed to %s%n", zoneString, zid);
}
Output:
UTC parsed to UTC
Pacific Standard Time parsed to America/Los_Angeles
Pacific/Honolulu parsed to Pacific/Honolulu
In the formatter I use zzzz is for time zone name like Pacific Standard Time. My parse method tries this formatter first. It fails for UTC and Pacific/Honolulu. When the DateTimeParseException is caught, the method next tries the ZoneId.of method also used in the other answers. It handles UTC and all the time zone ID sin region/city format mentioned in the documentation.
Combine the ZoneId obtained from my method with the parsed LocalDateTime to get a ZonedDateTime the way that deHaar is already showing in their answer.
I am creating date like this:
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
Date.from(now.toInstant());
I need Date object have current time in utc, but when I print date it gives me my local time and not utc time.
I also tried with:
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
Date date = Date.from(now.toInstant());
But when I print Date again time is not in utc. Am I doing something wrong when creating Date object. Why above 2 approaches not give me Date that have current time in utc.
Two points:
Avoid the long outdated Date class, in particular when you are already using classes from java.time, the modern Java date and time API.
A Date object hasn’t got and cannot have a time zone in it.
To print offset or time zone
If you need your offset, you need to hold on to your OffsetDateTime (or ZonedDateTime) object:
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println(now);
On my computer this just printed
2017-11-21T11:53:11.519Z
The Z in the end indicates Zulu time zone, another name for UTC (you may also informally think of it as Zero offset from UTC).
If you would like a more human-readable format, you are right, use a formatter:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
System.out.println(now.format(formatter));
Depending on your locale and the time, this prints something like
Tuesday, November 21, 2017 11:53:11 AM Z
Again the Z means Zulu time zone, UTC.
Date is not going to help you
A Date is just a point in time. So is the Instant that you use for initializing the date. None of them has got a time zone or offset. The difference here is their toString methods: The Instant is always printed in UTC, the Date usually (always?) in the JVM’s default time zone. The latter confuses many into thinking the Date has a time zone when it hasn’t. See All about java.util.Date.
As I have demonstrated, a formatter may put a time zone or offset into a string when formatting the date-time. This does not in any way modify the date-time object, whether OffsetDateTime, ZonedDateTime, Instant or Date. The long outdated DateFormat class may do the same when formatting a Date. It cannot and will not set a time zone in the Date object since (and I repeat) a Date object cannot have a time zone in it.
Long story short, you have no need for the outdated Date class that I can see.
correct date format i am looking for:- "2017-07-06T18:03:39.195+0530"
how to get the +0530 for the current date in java ?
when i am using SimpleDateFormat it is giving +0000 , while it should give +0530 .
=================================================
i have tried using below :-
SimpleDateFormat format = new SimpleDateFormat("enter code hereyyy-MM-dd HH:mm:ss.SSS Z");
String dateString = format.format(new Date());
System.out.println("value of dateString is :"+dateString);
the above code will output :-
value of dateString is :2017-07-10 06:51:27.250 +0000
while it should output : +0530
can you please tell me how can i get the +0530 offset for the above date or current date ?
tl;dr
ZonedDateTime.now( ZoneId.of( "Asia/Kolkata" ) ).toOffsetDateTime().toString()
OffsetDateTime
To directly address the Question, use the modern OffsetDateTime class.
OffsetDateTime.now().toString()
See this code run live at IdeOne.com.
odt.toString(): 2019-08-22T17:44:00.219684Z
That will generate a string representing the current moment in the offset used by the JVM’s current default time zone using standard ISO 8601 format. One difference: This method will include the optional COLON : character between hours and minutes of the offset. I suggest never omitting that character as I have seen multiple libraries break on such input, expecting the COLON to be there.
When capturing the current moment, the result may resolve to microseconds. If you prefer milliseconds, truncate, lopping off the micros.
OffsetDateTime.now().truncatedTo( ChronoUnit.MILLIS )
odtTruncated.toString(): 2019-08-22T17:44:00.219Z
That code running at IdeOne.com is in a JVM where the offset is set to zero, for UTC itself. So we see a Z at the end, a common and standard alternative to +00:00, pronounced “Zulu”.
You may want to specify your offset explicitly.
Instant instant = Instant.now() ; // Current moment in UTC.
ZoneOffset offset = ZoneId.of( "Asia/Kolkata" ).getRules().getOffset( instant ) ; // We must pass a moment. India is currently at five and a half hours ahead of UTC. But it has not always been so in the past, and may not always be so in the future.
OffsetDateTime odt = instant.atOffset( offset ) ;
odt.toString(): 2019-08-22T23:00:06.925139+05:30
I think a cleaner syntax is to use ZonedDateTime.
String output = ZonedDateTime.now( ZoneId.of( "Asia/Kolkata" ) ).toOffsetDateTime().toString() ;
2019-08-22T23:03:19.072681+05:30
ZonedDateTime
More likely you should be getting the current moment in a time zone rather than a mere offset. If so, see the Answer by RaT.
Be clear on the difference between offset and zone:
An offset-from-UTC is merely a number of hours-minutes-seconds ahead of UTC or behind UTC.
A time zone is much more. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region. A zone has a name in Continent/Region format, such as America/Montreal or Africa/Tunis.
Converting
Normally, you should avoid using the terrible date-time classes such as java.util.Date and SimpleDateFormat that are now legacy. Always use Instant, OffsetDateTime, and ZonedDateTime. Never use Date & Calendar.
But if you must you must use the legacy classes when interoperating with old code not yet updated for the java.time classes, you can convert back-and-forth. This is shown in the Answer by RaT.
You can Use Java 8 DateTime API for another solution
ZoneId zone = ZoneId.systemDefault(); //It will give current System's timezone (IST for you)
Date date = new Date(); // Any date
DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS Z", Locale.ENGLISH);
ZonedDateTime zonedTime = ZonedDateTime.ofInstant(date.toInstant(), zone);
System.out.println(zonedTime.format(formatter));
Above code will give you Date with correct Zone Offset
After a lot of searching I found that the timezone problem can be solved with Joda time API. You can use below code to achieve what I want in my question:
DateTime dateTime = DateTime.now();
System.out.println(dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
It outputs the current date with proper timezone:
2017-07-10T15:01:48.319+0530
Set the timezone you need. Your code would looke like:
SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS Z");
format.setTimeZone(TimeZone.getTimeZone("IST"));
String dateString = format.format(new Date());
System.out.println("value of dateString is :"+dateString);