I have a Date object which holds a date (not current date) and I need to somehow specify that this date is UTC and then convert it to "Europe/Paris" which is +1 hours.
public static LocalDateTime toLocalDateTime(Date date){
return ZonedDateTime.of(LocalDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC), ZoneId.of("Europe/Paris")).toLocalDateTime();
}
Given a date of "2018-11-08 15:00:00" this converts the date into "2018-11-08 14:00:00". I need it to convert from UTC to Europe/Paris - not the other way around.
You could use ZonedDateTime.withZoneSameInstant() method to move from UTC to Paris time:
Date date = new Date();
ZonedDateTime utc = date.toInstant().atZone(ZoneOffset.UTC);
ZonedDateTime paris = utc.withZoneSameInstant(ZoneId.of("Europe/Paris"));
System.out.println(utc);
System.out.println(paris);
System.out.println(paris.toLocalDateTime());
which prints:
2018-11-08T10:25:18.223Z
2018-11-08T11:25:18.223+01:00[Europe/Paris]
2018-11-08T11:25:18.223
Since an old-fashioned Date object doesn’t have any time zone, you can ignore UTC completely and just convert to Europe/Paris directly:
private static final ZoneId TARGET_ZONE = ZoneId.of("Europe/Paris");
public static LocalDateTime toLocalDateTime(Date date){
return date.toInstant().atZone(TARGET_ZONE).toLocalDateTime();
}
I’m not sure why you want to return a LocalDateTime, though. That is throwing away information. For most purposes I’d leave out .toLocalDateTime() and just return the ZonedDateTime from atZone.
ZonedId zoneId = ZoneId.of("Europe/Paris");
return ZonedDateTime.of(LocalDateTime.ofInstant(date.toInstant(),zonedId);
Try to define ZoneId that is Europe/Paris
Related
I have tried multiple ways one of them using SimpleDateFromatter and now trying
import java.sql.Timestamp;
public static String getCorrectTimeFormat(Timestamp time) {
return time.toInstant().toString();
}
But the problem is which I realized during writing unit test is, the time gets modified.
Timestamp timeStamp = Timestamp.valueOf("2020-07-22 12:26:51.599");
String res = UserUtil.getCorrectTimeFormat(timeStamp);
assertThat(res).isEqualTo("2020-07-22T12:26:51.599Z");
This never passes as the it auto converts to "2020-07-22T11:26:51.599Z"
It’s best to avoid jqva.sql.Timestamp completely. I’ll show you how.
The result you got is correct, as I think you have already discovered.
Get java.time types from your database
Since JDBC 4.2 we can directly get java.time types from a ResultSet. If your database value is a timestamp with time zone (recommended), for example:
OffsetDateTime odt = rs.getObject(
"your_timestamp_with_time_zone_column", OffsetDateTime.class);
String utcString = odt.withOffsetSameInstant(ZoneOffset.UTC).toString();
If your database value is a timestamp without time zone (not recommended), we can only get a LocalDateTime from it, which doesn’t define a point in time. To convert to Instant we need to rely on knowing which time zone the database uses. For example:
ZoneId datebaseTimeZone = ZoneId.of("Europe/Paris");
LocalDateTime ldt = rs.getObject(
"your_timestamp_column", LocalDateTime.class);
String utcString = ldt.atZone(datebaseTimeZone)
.withZoneSameInstant(ZoneOffset.UTC)
.toString();
If your database uses UTC, which counts as an offset, it’s better to use ZoneOffset than ZoneId:
ZoneOffset datebaseOffset = ZoneOffset.UTC;
LocalDateTime ldt = rs.getObject(
"your_timestamp_column", LocalDateTime.class);
String utcString = ldt.atOffset(datebaseOffset).toString();
Your observed result is correct
java.sql.Timestamp confusingly prints in the default time zone of the JVM, and Timestamp.valueOf() equally confusingly assumes that time zone. So assuming that your time zone is at offset +01:00 at this time of year (such as Great Britain, Ireland, Portugal, Morocco and Tunesia, for example), the conversion from 2020-07-22 12:26:51.599 to 2020-07-22T11:26:51.599Z is correct.
You can use java 8 time ZonedDateTime class :
//1 - default pattern
String timeStamp = "2019-03-27T10:15:30";
ZonedDateTime localTimeObj = ZonedDateTime.parse(time);
//2 - specified pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss a z");
String timeStamp1 = "2019-03-27 10:15:30 AM";
ZonedDateTime localTimeObj1 = ZonedDateTime.parse(timeStamp1, formatter);
//To get LocalDate from ZonedDateTime
LocalDate localDate = localTimeObj1.toLocalDate()
//To get timestamp from zoneddatetime with utc timezone
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
In the database, a time is saved as a Timestamp in the UTC time zone (that is, 0). When I get it, I need to add the Timezone from the place that I will send. I have these two pieces of information, but I can't find the time.
This is the code from which I get both information. I've tried to transform to LocalDateTime and adjust the zone, but it didn't produce any results. There is no much of code:
Timestamp timestamp = resultQueryCamerasOffline.getLastOnline();
String zoneId = resultQueryCamerasOffline.getEmpresaTimezone();
System.out.println(timestamp.toString());
System.out.println(zoneId);
2020-03-12 03:01:45.0
America/São_Paulo
In the database, last_online has value:
2020-03-12 03:01:45.0
You can and maybe have to use a LocalDateTime in order to achieve what you want, but the final product should be a ZonedDateTime.
Basically, the timestamp should be converted to a LocalDateTime and that LocalDateTime can then be converted to a ZonedDateTime by adding a specific ZoneId, like this:
Just adding a zone, leaving the datetime as is:
public static void main(String[] args) {
// get or take a timestamp
java.sql.Timestamp timestamp = Timestamp.valueOf("2020-03-12 03:01:45.0");
// transforming it into a LocalDateTime
LocalDateTime localDateTime = timestamp.toLocalDateTime();
// now create a ZonedDateTime by putting a zone
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime,
ZoneId.of("America/Sao_Paulo"));
// and print the result
System.out.println(zonedDateTime);
}
The output is
2020-03-12T03:01:45-03:00[America/Sao_Paulo]
If you are sure the client that runs this code always has the desired time zone, then you can alternatively use ZoneId.systemDefault() when the ZonedDateTime is being created.
But if you don't just want to add a zone but really convert the Instant to another zone, then you can do this:
Converting the Instant to another time zone:
public static void main(String[] args) {
// get or take a timestamp
java.sql.Timestamp timestamp = Timestamp.valueOf("2020-03-12 03:01:45.0");
// transforming it into a LocalDateTime
LocalDateTime localDateTime = timestamp.toLocalDateTime();
// now create a ZonedDateTime by putting a zone
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
localDateTime.toInstant(ZoneOffset.of("+00:00")),
ZoneId.of("America/Sao_Paulo"));
// and print the result
System.out.println(zonedDateTime);
}
This outputs
2020-03-12T00:01:45-03:00[America/Sao_Paulo]
You can have the second one shorter:
public static void main(String[] args) {
// get or take a timestamp
java.sql.Timestamp timestamp = Timestamp.valueOf("2020-03-12 03:01:45.0");
// transforming it into a LocalDateTime
ZonedDateTime utc = ZonedDateTime.of(timestamp.toLocalDateTime(), ZoneId.of("UTC"));
// now create a ZonedDateTime by putting a zone
ZonedDateTime saoPaulo = utc.withZoneSameInstant(ZoneId.of("America/Sao_Paulo"));
// and print the result
System.out.println(saoPaulo);
}
The output stays
2020-03-12T00:01:45-03:00[America/Sao_Paulo]
If you want the output formatted differently, you have to either choose one of the built-in patterns (public constants of DateTimeFormatter, like DateTimeFormatter.ISO_ZONED_DATE_TIME) or give it a custom one (by DateTimeFormatter.ofPattern(String pattern) plus an optional Locale):
public static void main(String[] args) {
// get or take a timestamp
java.sql.Timestamp timestamp = Timestamp.valueOf("2020-03-12 03:01:45.0");
// transforming it into a LocalDateTime
ZonedDateTime utc = ZonedDateTime.of(timestamp.toLocalDateTime(), ZoneId.of("UTC"));
// now create a ZonedDateTime by putting a zone
ZonedDateTime saoPaulo = utc.withZoneSameInstant(ZoneId.of("America/Sao_Paulo"));
// create a formatter for your locale and with the desired pattern
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEEE dd MMM yyyy hh:mm:ss a xxx",
Locale.forLanguageTag("pt-BR"));
// and print the result
System.out.println(saoPaulo.format(dtf));
}
This time, the output is formatted in a totally different way:
Quinta-feira 12 mar 2020 12:01:45 AM -03:00
get the millis from your timestamp and try:
LocalDateTime date = LocalDateTime
.ofInstant(Instant.ofEpochMilli(timestamp.getTime()), ZoneId.systemDefault(yourTimezone()));
or try using a ZonedDateTime
Hi i am currently work on creating Desktop application using Swing.I was able to convert IST to EST time using Date class in java but not able to convert EST to IST time and it gives same EST time as IST time. Please find the below code .
ChangetoEST function is giving correct EST time from IST time.
ChangetoIST function is not giving correct IST time from EST time and showing given EST time as IST time.
public String changetoEST(String date) throws ParseException
{
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String dateInString = date;
Date d=formatter.parse(dateInString);
TimeZone tzInAmerica = TimeZone.getTimeZone("America/New_York");
formatter.setTimeZone(tzInAmerica);
String sDateInAmerica = formatter.format(d);
Date dateInAmerica = formatter.parse(sDateInAmerica);
String a=formatter.format(dateInAmerica);
return a;
}
public String changetoIST(String date) throws ParseException
{
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String dateInString = date;
Date d=formatter.parse(dateInString);
TimeZone tzInIndian = TimeZone.getTimeZone("Asia/Calcutta");
formatter.setTimeZone(tzInIndian);
String sDateInAmerica = formatter.format(d);
Date dateInAmerica = formatter.parse(sDateInAmerica);
String a=formatter.format(dateInAmerica);
return a;
}
The parse calls are done without you explicitly setting a time zone, which means that parsing is done using your default time zone.
Set the source time zone before parsing, parse, set time zone to target time zone, and format result.
E.g.
public static String istToEst(String dateInput) throws ParseException {
return changeTimeZone(dateInput, TimeZone.getTimeZone("Asia/Calcutta"),
TimeZone.getTimeZone("America/New_York"));
}
public static String estToIst(String dateInput) throws ParseException {
return changeTimeZone(dateInput, TimeZone.getTimeZone("America/New_York"),
TimeZone.getTimeZone("Asia/Calcutta"));
}
private static String changeTimeZone(String dateInput, TimeZone sourceTimeZone,
TimeZone targetTimeZone) throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
formatter.setTimeZone(sourceTimeZone);
Date date = formatter.parse(dateInput);
formatter.setTimeZone(targetTimeZone);
return formatter.format(date);
}
Test
String dateInput = "08/22/2016 02:21 AM";
System.out.println(dateInput);
System.out.println(istToEst("08/22/2016 02:21 AM"));
System.out.println(estToIst("08/22/2016 02:21 AM"));
Output
08/22/2016 02:21 AM
08/21/2016 04:51 PM
08/22/2016 11:51 AM
Set formatter to the source timezone before parsing (this is the step you are missing), then set it to the destination timezone before formatting, otherwise it parses it using the local timezone, which is IST for you.
Also you should just be able to return sDateInAmerica directly, you don't need to re-parse then re-format it a second time.
java.time
You are using troublesome old legacy date-time classes, now supplanted by the java.time classes.
We parse the input string as a LocalDateTime as it lacks any info about offset-from-UTC or time zone (offset plus rules for anomalies such as DST).
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/yyyy hh:mm a" );
LocalDateTime ldt = LocalDateTime.parse( input , f );
Apply a time zone to get an actual moment on the timeline, a ZonedDateTime object.
ZoneId zNewYork = ZoneId.of( "America/New_York" );
ZonedDateTime zdtNewYork = ldt.atZone( zNewYork );
To see the same moment through the lens of another time zone, another wall-clock time, adjust into another ZoneId. Notice that we are not going through another LocalDateTime as the purpose of that class is to forget any information about offset or time zone. We want the opposite, to use the info about time zone to adjust wisely between zones. So while New York is behind UTC by four hours, India is ahead of UTC by five and a half hours. So we need a total of nine and a half hour adjustment, which may include a change in date.
ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdtKolkata = zdtNewYork.withZoneSameInstant( zKolkata ); // Same simultaneous moments on the timeline.
Generate String
You can generate a String in any format you desire to represent the date-time value.
String output = zdtKolkata.format( f );
Generally better to let java.time automatically localize for you.
Locale l = Locale.CANADA_FRENCH; // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( l );
String output = zdtKolkata.format( f );
Java 8 has a completely new API for date and time. One of the most useful classes in this API is LocalDateTime, for holding a timezone-independent date-with-time value.
There are probably millions of lines of code using the legacy class java.util.Date for this purpose. As such, when interfacing old and new code there will be a need for converting between the two. As there seems to be no direct methods for accomplishing this, how can it be done?
Short answer:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
Explanation:
(based on this question about LocalDate)
Despite its name, java.util.Date represents an instant on the time-line, not a "date". The actual data stored within the object is a long count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).
The equivalent class to java.util.Date in JSR-310 is Instant, thus there are convenient methods to provide the conversion to and fro:
Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);
A java.util.Date instance has no concept of time-zone. This might seem strange if you call toString() on a java.util.Date, because the toString is relative to a time-zone. However that method actually uses Java's default time-zone on the fly to provide the string. The time-zone is not part of the actual state of java.util.Date.
An Instant also does not contain any information about the time-zone. Thus, to convert from an Instant to a local date-time it is necessary to specify a time-zone. This might be the default zone - ZoneId.systemDefault() - or it might be a time-zone that your application controls, such as a time-zone from user preferences. LocalDateTime has a convenient factory method that takes both the instant and time-zone:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
In reverse, the LocalDateTime the time-zone is specified by calling the atZone(ZoneId) method. The ZonedDateTime can then be converted directly to an Instant:
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
Note that the conversion from LocalDateTime to ZonedDateTime has the potential to introduce unexpected behaviour. This is because not every local date-time exists due to Daylight Saving Time. In autumn/fall, there is an overlap in the local time-line where the same local date-time occurs twice. In spring, there is a gap, where an hour disappears. See the Javadoc of atZone(ZoneId) for more the definition of what the conversion will do.
Summary, if you round-trip a java.util.Date to a LocalDateTime and back to a java.util.Date you may end up with a different instant due to Daylight Saving Time.
Additional info: There is another difference that will affect very old dates. java.util.Date uses a calendar that changes at October 15, 1582, with dates before that using the Julian calendar instead of the Gregorian one. By contrast, java.time.* uses the ISO calendar system (equivalent to the Gregorian) for all time. In most use cases, the ISO calendar system is what you want, but you may see odd effects when comparing dates before year 1582.
Here is what I came up with ( and like all Date Time conundrums it is probably going to be disproved based on some weird timezone-leapyear-daylight adjustment :D )
Round-tripping: Date <<->> LocalDateTime
Given: Date date = [some date]
(1) LocalDateTime << Instant<< Date
Instant instant = Instant.ofEpochMilli(date.getTime());
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
(2) Date << Instant << LocalDateTime
Instant instant = ldt.toInstant(ZoneOffset.UTC);
Date date = Date.from(instant);
Example:
Given:
Date date = new Date();
System.out.println(date + " long: " + date.getTime());
(1) LocalDateTime << Instant<< Date:
Create Instant from Date:
Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);
Create Date from Instant (not necessary,but for illustration):
date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());
Create LocalDateTime from Instant
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);
(2) Date << Instant << LocalDateTime
Create Instant from LocalDateTime:
instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);
Create Date from Instant:
date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());
The output is:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Instant from Date:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
LocalDateTime from Instant:
2013-11-01T14:13:04.574
Instant from LocalDateTime:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Much more convenient way if you are sure you need a default timezone :
Date d = java.sql.Timestamp.valueOf( myLocalDateTime );
The fastest way for LocalDateTime -> Date is:
Date.from(ldt.toInstant(ZoneOffset.UTC))
Everything is here : http://blog.progs.be/542/date-to-java-time
The answer with "round-tripping" is not exact : when you do
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
if your system timezone is not UTC/GMT, you change the time !
the following seems to work when converting from new API LocalDateTime into java.util.date:
Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());
the reverse conversion can be (hopefully) achieved similar way...
hope it helps...
If you are on android and using threetenbp you can use DateTimeUtils instead.
ex:
Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
you can't use Date.from since it's only supported on api 26+
I'm not sure if this is the simplest or best way, or if there are any pitfalls, but it works:
static public LocalDateTime toLdt(Date date) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
ZonedDateTime zdt = cal.toZonedDateTime();
return zdt.toLocalDateTime();
}
static public Date fromLdt(LocalDateTime ldt) {
ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
GregorianCalendar cal = GregorianCalendar.from(zdt);
return cal.getTime();
}
I think below approach will solve the conversion without taking time-zone into consideration.
Please comment if it has any pitfalls.
LocalDateTime datetime //input
public static final DateTimeFormatter yyyyMMddHHmmss_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatDateTime = datetime.format(yyyyMMddHHmmss_DATE_FORMAT);
Date outputDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(formatDateTime); //output
I'm retrieving a timestamp object from a database using ResultSet.getTimestamp(), but I'd like an easy way to get the date in the format of MM/DD/YYYY and the time in a format of HH:MM xx. I was tinkering around, it it looks as though I can do such by making use of the Date and/or DateTime objects within Java. Is that the best way to go, or do I even need to convert the timestamp to accomplish this? Any recommendations would be helpful.
....
while(resultSet.next()) {
Timestamp dtStart = resultSet.getTimestamp("dtStart");
Timestamp dtEnd = resultSet.getTimestamp("dtEnd");
// I would like to then have the date and time
// converted into the formats mentioned...
....
}
....
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Date date = new Date(timestamp.getTime());
// S is the millisecond
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/yyyy' 'HH:mm:ss:S");
System.out.println(simpleDateFormat.format(timestamp));
System.out.println(simpleDateFormat.format(date));
}
}
java.sql.Timestamp is a subclass of java.util.Date. So, just upcast it.
Date dtStart = resultSet.getTimestamp("dtStart");
Date dtEnd = resultSet.getTimestamp("dtEnd");
Using SimpleDateFormat and creating Joda DateTime should be straightforward from this point on.
java.time
Modern answer: use java.time, the modern Java date and time API, for your date and time work. Back in 2011 it was right to use the Timestamp class, but since JDBC 4.2 it is no longer advised.
For your work we need a time zone and a couple of formatters. We may as well declare them static:
static ZoneId zone = ZoneId.of("America/Marigot");
static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM/dd/uuuu");
static DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm xx");
Now the code could be for example:
while(resultSet.next()) {
ZonedDateTime dtStart = resultSet.getObject("dtStart", OffsetDateTime.class)
.atZoneSameInstant(zone);
// I would like to then have the date and time
// converted into the formats mentioned...
String dateFormatted = dtStart.format(dateFormatter);
String timeFormatted = dtStart.format(timeFormatter);
System.out.format("Date: %s; time: %s%n", dateFormatted, timeFormatted);
}
Example output (using the time your question was asked):
Date: 09/20/2011; time: 18:13 -0400
In your database timestamp with time zone is recommended for timestamps. If this is what you’ve got, retrieve an OffsetDateTime as I am doing in the code. I am also converting the retrieved value to the user’s time zone before formatting date and time separately. As time zone I supplied America/Marigot as an example, please supply your own. You may also leave out the time zone conversion if you don’t want any, of course.
If the datatype in SQL is a mere timestamp without time zone, retrieve a LocalDateTime instead. For example:
ZonedDateTime dtStart = resultSet.getObject("dtStart", LocalDateTime.class)
.atZone(zone);
No matter the details I trust you to do similarly for dtEnd.
I wasn’t sure what you meant by the xx in HH:MM xx. I just left it in the format pattern string, which yields the UTC offset in hours and minutes without colon.
Link: Oracle tutorial: Date Time explaining how to use java.time.
You can also get DateTime object from timestamp, including your current daylight saving time:
public DateTime getDateTimeFromTimestamp(Long value) {
TimeZone timeZone = TimeZone.getDefault();
long offset = timeZone.getOffset(value);
if (offset < 0) {
value -= offset;
} else {
value += offset;
}
return new DateTime(value);
}
LocalDateTime dtStart = rs.getTimestamp("dtStart").toLocalDateTime();
Converts this Timestamp object to a code LocalDateTime.
The conversion creates a code LocalDateTime that represents the
same year, month, day of month, hours, minutes, seconds and nanos
date-time value as this code Timestamp in the local time zone.
since 1.8