switch between ofEpochMilli and ofEpochSecond - java

In my application one of third party API returning timestamp in epoch.
Sometime it returns epoch time in seconds and sometime in miliseconds not confirmed. My application using below code to
convert it to java date and display to user but when I am receiving time in miliseconds it is failing on year.
String time = "1519377196185"; //Time in miliseconds
//String time = "1521575819"; //Time in seconds.
String timeZone = "US/Pacific";
long epochdate = Long.parseLong(time);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yyyy hh:mm a");
LocalDateTime date34 =
Instant.ofEpochSecond(epochdate)
.atZone(ZoneId.of(timeZone))
.toLocalDateTime();
String date = date34.format(formatter).toString();
System.out.println("date : " + date);
if I use Instant.ofEpochMilli(epochdate) for miliseconds then it is working fine. So my question is how I can know that coming timestamp is in miliseconds or seconds so on that basis I will switch between ofEpochMilli and ofEpochSecond

Year Offset
I would try to parse first the date as seconds, given that if the date is in millis the year would be something extremely big (in this case 50000), then if the year is not greater than the year defined offset (e.g. 3000), that date is returned, otherwise the date is returned as millis.
public ZonedDateTime getZonedDateTime(String time) {
long longTime = Long.parseLong(time), yearOffset = 3000L;
String timeZone = "US/Pacific";
ZoneId zoneId = ZoneId.of(timeZone);
ZonedDateTime zdt = Instant.ofEpochSecond(longTime).atZone(zoneId);
if (zdt.getLong(ChronoField.YEAR_OF_ERA) >= yearOffset) {
return Instant.ofEpochMilli(longTime).atZone(zoneId);
} else {
return zdt;
}
}
Using the functions prints:
getZonedDateTime("1519377196185"); // 2018-02-23T01:13:16.185-08:00[US/Pacific]
getZonedDateTime("1521575819"); // 2018-03-20T12:56:59-07:00[US/Pacific]
Margin of Error
Any method that you decide to use, would have the possibility of an error and that the date is transformed incorrectly, specially when the date is in milliseconds and is too close of the epoch 1970-01-01T00:00:00Z.
The margin errors using the year offset of 3000 would be:
When the date is originally in milliseconds in the range from 1970-01-01T00:00:00Z until 1971-01-12T04:48:00Z
Would be considered as date in seconds
When the date is originally in seconds and the date is equal or after 3000-01-01T00:00:00Z (improbable date in normal apps)
Would be considered as date in milliseconds
Calculate the range of error in milliseconds dates
You can calculate the range of error for dates originally in milliseconds with:
Instant.ofEpochMilli(LocalDateTime.of(3000, 1, 1, 0, 0) // year = 3000
.toEpochSecond(ZoneOffset.UTC)); // 1971-01-12T04:48:00Z

One easy (temporary, sort of) solution would be to just check the length of your time String. If the length is equal to 13, then it represents milliseconds. This will be true until 1 ms after 2286-11-20T17:46:39.999Z, which is a long time from now. The time in seconds would take even more time to reach a length of 13.

Inspect length of String input
As stated by Jacob G. his Answer, check the length.
String input = "1519377196185"; // Milliseconds since epoch.
//String input = "1519377196" ; // Seconds since epoch.
Instant instant = null;
int length = input.length();
switch ( length )
{
case 13:
instant = Instant.ofEpochMilli( Long.parseLong( input ) );
break;
case 10:
instant = Instant.ofEpochSecond( Long.parseLong( input ) );
break;
default:
throw new IllegalStateException( "Unexpected length of input text for count-from-epoch number: " + input + ". Message # 2188d054-5720-4393-9b18-829913d7ba1c." );
}
System.out.println( input + " ➞ " + instant.toString() ); // Generate a String representing textually the value of the `Instant` object.
1519377196185 ➞ 2018-02-23T09:13:16.185Z
Or:
1519377196 ➞ 2018-02-23T09:13:16Z
ZonedDateTime
To move from UTC in an Instant to some particular time zone, provide the context of a time zone (ZoneId) to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2018-02-23T10:13:16.185+01:00[Africa/Tunis]
LocalDateTime - not appropriate here
The LocalDateTime class is the wrong class to use, as seen in the Question. This class purposely lacks any concept of time zone or offset-from-UTC. So it does not represent a moment, and is not a point on the timeline. This class represents potential moments along a range of about 26-27 hours.
Use LocalDateTime only when the zone/offset is unknown (a terrible situation) or when you need an indefinite value such as “Christmas starts on first moment of December 25, 2018”.

You can solve this other way by converting epoch in seconds to epoch in milliseconds and apply only Instant.ofEpochMilli() for both:
String time = "1519377196185"; //Time in miliseconds or seconds
if(time.length() == 10) { // length of epoch in seconds is 10
time = time + "000";
}
String timeZone = "US/Pacific";
long epochdate = Long.parseLong(time);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yyyy hh:mm a");
LocalDateTime date34 = Instant.ofEpochMilli(time)
.atZone(ZoneId.of(timeZone))
.toLocalDateTime();
String date = date34.format(formatter).toString();
System.out.println("date: " + date);

Related

converting timestamp date to unix timestamp

i have data like this one
date what i got from timestamp utc are : 2020-06-29 05:31:58.153
LocalDateTime timestampasstring = message.getHeader().getUtcTimeStamp( SendingTime.FIELD);
Timestamp timestamp = Timestamp.from(timestampasstring.toInstant(ZoneOffset.UTC));
System.out.println(timestamp);
String timestampstrings = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
String timestampstrings2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(timestamp);
i need to get timestamp number like 2020-06-29 05:31:58
and convert it become unix timestamp like this one 1593408718
how to convert it ?
If your getUtcTimeStamp method is helpful enough to return a LocalDateTime, you're most of the way there. Convert to an Instant using ldt.atOffset(ZoneOffset.UTC) (your getUtcTimeStamp really should be doing this for you if it already knows it's in UTC), then just call toEpochSecond() (or toEpochMilli() if you want the milliseconds part, but you just showed whole seconds).
Having read your question, I assume your method message.getHeader().getUtcTimeStamp(SendingTime.FIELD) returns a String (not a LocalDateTime) representing a timestamp in UTC while being formatted either like 2020-06-29 05:31:58.153 or 2020-06-29 05:31:58.
Since you have (shown) differently formatted datetimes (respectively, datetimes with a different accuracy), you will have to take care of that by defining a suitable DateTimeFormatter using a pattern able to deal with optional milliseconds (yyyy-MM-dd HH:mm:ss[.SSS]).
You can use it as follows:
public static void main(String[] args) {
// receive the result from your message, this is just an example
String utcTimestamp = "2020-06-29 05:31:58";
// create a ZonedDateTime by parsing the String to a LocalDateTime and adding a time zone
ZonedDateTime zdt = LocalDateTime.parse(utcTimestamp,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]"))
.atZone(ZoneId.of("UTC"));
// then get the epoch milliseconds / unix timestamp
long millis = zdt.toInstant().toEpochMilli();
// and print the result
System.out.println(zdt + " ==> " + millis + " epoch millis");
}
The output of this is, of course, different for datetimes that are only equal down to seconds:
2020-06-29T05:31:58Z[UTC] ==> 1593408718000 epoch millis
2020-06-29T05:31:58.153Z[UTC] ==> 1593408718153 epoch millis
If you call long seconds = zdt.toEpochSeconds() instead of converting toInstant().toEpochMillis (and adjust the output a little) you will get the same value for both examples:
public static void main(String[] args) {
// receive the result from your message, this is just an example
String utcTimestamp = "2020-06-29 05:31:58.153";
// create a ZonedDateTime by parsing the String to a LocalDateTime and adding a time zone
ZonedDateTime zdt = LocalDateTime.parse(utcTimestamp,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]"))
.atZone(ZoneId.of("UTC"));
// then get the epoch seconds
long seconds = zdt.toEpochSecond();
// and print the result
System.out.println(zdt + "\t==>\t" + seconds + " epoch seconds");
}
Output:
2020-06-29T05:31:58Z[UTC] ==> 1593408718 epoch seconds
2020-06-29T05:31:58.153Z[UTC] ==> 1593408718 epoch seconds
If your method really returns a LocalDateTime, you could simply skip conversions and write
public static void main(String[] args) {
LocalDateTime utcDateTime = message.getHeader().getUtcTimeStamp(SendingTime.FIELD);
// then get the epoch seconds
long seconds = utcDateTime.atZone(ZoneId.of("UTC")).toEpochSecond();
// and print the result
System.out.println(utcDateTime + "\t==>\t" + seconds + " epoch seconds");
}
The other answers are fine. Here’s my variant. First declare a formatter for parsing:
private DateTimeFormatter timestampFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter();
Consider declaring the formatter static and/or final. With this formatter I’d do:
String timestampAsString = "2020-06-29 05:31:58.153";
OffsetDateTime dateTime = LocalDateTime
.parse(timestampAsString, timestampFormatter)
.atOffset(ZoneOffset.UTC);
long unixTimestamp = dateTime.toEpochSecond();
System.out.println(unixTimestamp);
Output is what you asked for:
1593408718
The nice thing about the formatter is that it accepts both 2020-06-29 05:31:58.153 and 2020-06-29 05:31:58, that is, time both with and without fraction of second, and with any fraction of from 1 up to 9 decimals. Reusing ISO_LOCAL_TIME in the formatter buys us this.

How to manipulate Instant to add two days and string based time? [duplicate]

I have two java.time.Instant objects
Instant dt1;
Instant dt2;
I want to get time (only hours and minutes without date) from dt2 and set it to dt1. What is the best way to to this? Using
dt2.get(ChronoField.HOUR_OF_DAY)
throws java.time.temporal.UnsupportedTemporalTypeException
You have to interpret the Instant at some time zone to get ZonedDateTime. As an Instant measures the ellapsed seconds and nano seconds from epoch 1970-01-01T00:00:00Z you should use UTC to get the same time as the Instant would print. (Z ≙ Zulu Time ≙ UTC)
Getting the time
Instant instant;
// get overall time
LocalTime time = instant.atZone(ZoneOffset.UTC).toLocalTime();
// get hour
int hour = instant.atZone(ZoneOffset.UTC).getHour();
// get minute
int minute = instant.atZone(ZoneOffset.UTC).getMinute();
// get second
int second = instant.atZone(ZoneOffset.UTC).getSecond();
// get nano
int nano = instant.atZone(ZoneOffset.UTC).getNano();
There are also methods to get days, month and year (getX).
Setting the time
Instants are immutable so you can only "set" the time by creating a copy of your instant with the given time change.
instant = instant.atZone(ZoneOffset.UTC)
.withHour(hour)
.withMinute(minute)
.withSecond(second)
.withNano(nano)
.toInstant();
There are also methods to alter days, month and year (withX) as well as methods to add (plusX) or subtract (minusX) time or date values.
To set the time to a value given as a string use: .with(LocalTime.parse("12:45:30"))
Instant does not have any hour / minute. Please read the documentation of Instant class : https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html
If you use System Timezone to convert the Instant , you can use something like this :
LocalDateTime ldt1 = LocalDateTime.ofInstant(dt1, ZoneId.systemDefault());
LocalDateTime ldt2 = LocalDateTime.ofInstant(dt2, ZoneId.systemDefault());
ldt1 = ldt1
.withHour(ldt2.getHour())
.withMinute(ldt2.getMinute())
.withSecond(ldt2.getSecond());
dt1 = ldt1.atZone(ZoneId.systemDefault()).toInstant();
Convert first the Instant to LocalDateTime, and use UTC as its timezone, then you can get its hours.
import java.time.*
LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC).getHour()
While the upper answer is a good, I used it but in Kotlin. Thankyou #frido
while (startDate.isBefore(endDate)) {
val year: Int = startDate.atZone(ZoneOffset.UTC).year
val month: Int = startDate.atZone(ZoneOffset.UTC).monthValue
val day: Int = startDate.atZone(ZoneOffset.UTC).dayOfMonth
System.out.printf("%d.%d.%d\n", day, month, year)
startDate = startDate.atZone(ZoneOffset.UTC).withDayOfMonth(
day + 1
).toInstant()
}

trying to convert timestamp to time with data type as int

Trying to convert timestamp to time with any zone using java, here I'm able to convert using ZoneID but it will return string data type. here I'm expecting output like getTimeMillis()
Instant now = Instant.ofEpochMilli(lngDate);
ZoneId zoneId = ZoneId.of("America/Chicago");
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, zoneId);
DateTimeFormatter isoDateFormatter = DateTimeFormatter.ISO_DATE_TIME;
String zdt = zonedDateTime.format(isoDateFormatter);
Here I'm expecting only time millis (8-digits number) and below giving you my code can you please help to solve it.
Input : 1552979609000L
DateTimeFormatter isoDateFormatter = DateTimeFormatter.ISO_TIME;
String zdt = zonedDateTime.format(isoDateFormatter); // output in string : 00:13:29-07:00
LocalTime time = LocalTime.parse(zdt, isoDateFormatter); // output in local time : 00:13:29
If I understand correctly, you want the millisecond of the day, in other words, the count of milliseconds since 00:00:00 as in int from 0 (inclusive) to 86 400 000 (exclusive; up to 8 digits). The ChronoField enum has a constant for that, so it’s straightforward when you know how:
int millisecondOfDay = zonedDateTime.get(ChronoField.MILLI_OF_DAY);
System.out.println("Millisecond of day: " + millisecondOfDay);
Output when running just now:
Millisecond of day: 7773854

Using Joda-Time to get UTC offset for a given date and timezone

I have dates in the format 20Jan2013, 08Aug2012 etc, with their own specific timezones. So for example, 20Jan2013 might have a timezone ID of Australia/Melbourne, and 08Aug2012 might have an ID of Europe/London. What I want to do is, based on these timezones and the dates, calculate the UTC offset for that timezone on the given date. I've come up with this so far:
DateTimeFormatter dtf = DateTimeFormat.forPattern("ZZ");
DateTimeFormatter dtf1 = DateTimeFormat.forPattern("ddMMMYYYY");
DateTimeZone zone = DateTimeZone.forID("Australia/Melbourne");
DateTime thisDate = dtf1.parseDateTime("30Jul2013");
System.out.println("\nZone: " + thisDate.withZone(zone));
This gives me the output:
Zone: 2013-07-30T00:00:00.000+10:00
This is correct, but I would like to extract just the UTC offset from this, which in this case is +10:00. I've looked for ways to do this but can't find anything. Is there any way I can do this? The only option I see is to convert the output to a String and use the substring method to get the UTC offset.
The above code does take DST (Daylight Saving Time) into account. So for example if I had:
DateTime thisDate = dtf1.parseDateTime("30Jan2013");
The output would be: 2013-01-30T00:00:00.000+11:00
(+11:00 at the end instead of +10:00)
So basically all I need to do is find a way to extract +11:00 from 2013-07-30T00:00:00.000+11:00. Please help!
Simple Method for Obtaining Timezone Name and Offset in Hours
public static String getCurrentTimeZoneOffset() {
DateTimeZone tz = DateTimeZone.getDefault();
Long instant = DateTime.now().getMillis();
String name = tz.getName(instant);
long offsetInMilliseconds = tz.getOffset(instant);
long hours = TimeUnit.MILLISECONDS.toHours( offsetInMilliseconds );
String offset = Long.toString( hours );
return name + " (" + offset + " Hours)";
// Example: "Mountain Standard Time (-7 Hours)"
}
Couple caveats:
This gets the default DateTimeZone from JodaTime. You can modify it to accept a specific DateTimeZone that is passed into the method.
This returns it in a format like "Mountain Standard Time (-7 Hours)" but you can format it as you see fit quite easily.
Hope that helps.
JP
In order for Joda to give the correct offset, you must provide a datetime instant.Without a datetime instant, it is impossible to calculate the offset since we have different offsets(daylight savings). This is how I would use Joda to get offset in + HH:mm format :
int offsetInMillis = DateTimeZone.forID(zoneId).getOffset(new DateTime().getMillis());
String offset = String.format("%02d:%02d", Math.abs(offsetInMillis / 3600000),
Math.abs((offsetInMillis / 60000) % 60));
offset = (offsetInMillis >= 0 ? "+" : "-") + offset;
If you just need the timezone offset, use DateTimeZone.forID() to get the time zone and then tz.getOffset(instant) to get the offset to UTC in milliseconds.
It may look odd that you need an instant to calculate the offset to UTC but this is necessary to take Daylight Savings into account as well as changes in the timezone. Yes, countries change their timezones once in a while:
Why does timezone data change?
Timezone settings are adopted locally, and there is no world timezone authority.
EDIT This gives you the correct result:
DateTimeFormatter dtf1 = DateTimeFormat.forPattern("ddMMMYYYY");
DateTimeZone zone = DateTimeZone.forID("Australia/Melbourne");
DateTime thisDate = dtf1.parseDateTime("30Jul2013").withZone(zone);
assertEquals( 10 * CommonConstants.MILLISECONDS_PER_HOUR,
zone.getOffset( thisDate ) );
thisDate.get
Java 8 introduced better Date and Time handling to address some of the language's previous limitations in that area. A few of my projects have started to use it rather than Joda.
Using the java.time package:
ZonedDateTime dateTime = LocalDate.of(2013 , 1 , 20).atStartOfDay( ZoneId.of("Australia/Melbourne"));
ZoneOffset zo = dateTime.getOffset();
int offset = zo.getTotalSeconds();
long hours = TimeUnit.SECONDS.toHours(offset);
long minutes = TimeUnit.SECONDS.toMinutes(offset % 3600);
The hours variable is set to 11 and the minutes to 0.
It also calculates the minutes-offset, for time zones that are partial hours, such as Newfoundland and Labrador in eastern Canada:
ZonedDateTime dateTime = LocalDate.of(2013, 1, 20).atStartOfDay( ZoneId.of("Canada/Newfoundland"));
In this case, the offset is -03:30 (three and a half hours behind UTC), hours is -3 and minutes is -30.
For the String representation, rather than the integer number of hours and minutes, use the ZoneOffset's toString() method. So for the example above, use:
String offsetString = zo.toString();
When you know offset and timestamp so in order to get current time you can use
public static String formatMonthDayMinuteByGivenUtcOffset(long timestamp, int offset) {
return JODA_FORMATTER.print(createDateTime(timestamp, offset));
}

How to convert date time from one time zone to another time zone

The records are getting saved according to time zone of US but if I want to show the same record back to user it should convert the server date time with(US Time Zone) to user's date time with user's Time Zone
If you type in google "Java date change timezone" or "Javascript date change timezone". You will have one of your results:
In Java (source: http://www.coderanch.com/t/417443/java/java/Convert-Date-one-timezone-another )
Date date = new Date();
DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
formatter.setTimeZone(TimeZone.getTimeZone("CET"));
// Prints the date in the CET timezone
System.out.println(formatter.format(date));
// Set the formatter to use a different timezone
formatter.setTimeZone(TimeZone.getTimeZone("IST"));
// Prints the date in the IST timezone
System.out.println(formatter.format(date));
Javascript (source: http://www.techrepublic.com/article/convert-the-local-time-to-another-time-zone-with-this-javascript/6016329 )
// function to calculate local time
// in a different city
// given the city's UTC offset
function calcTime(city, offset) {
// create Date object for current location
d = new Date();
// convert to msec
// add local time zone offset
// get UTC time in msec
utc = d.getTime() + (d.getTimezoneOffset() * 60000);
// create new Date object for different city
// using supplied offset
nd = new Date(utc + (3600000*offset));
// return time as a string
return "The local time in " + city + " is " + nd.toLocaleString();
}
// get Bombay time
alert(calcTime('Bombay', '+5.5'));
java.time
The old date-time classes are poorly designed, confusing, and troublesome. Avoid them.
Use modern classes: the java.time framework built into Java 8 and later. Find back-ports for earlier Java 6 & 7 and for Android.
An Instant is a moment on the timeline in UTC.
Instant now = Instant.now();
Apply a time zone (ZoneId) to get a ZonedDateTime.
Never use the 3-4 letter zone abbreviations such as EST or IST. They are neither standardized nor unique(!). Use proper time zone names, built in a continent/region format such as Asia/Kolkata, Pacific/Auckland, America/Los_Angeles.
ZoneId zoneId_Montreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt_Montreal = ZonedDateTime.ofInstant( instant , zoneId_Montreal );
Apply a different time zone to generate another ZonedDateTime adjusted to that time zone. Call withZoneSameInstant.
ZoneId zoneId_Paris = ZoneId.of( "Europe/Paris" ); // Or "Asia/Kolkata", etc.
ZonedDateTime zdt_Paris = zdt_Montreal.withZoneSameInstant( zoneId_Paris );
If you want to go back to UTC, ask for an Instant.
Instant instant = zdt_Paris.toInstant();
TimeZone fromTimezone =TimeZone.getTimeZone(from);
TimeZone toTimezone=TimeZone.getTimeZone(to);
long fromOffset = fromTimezone.getOffset(calendar.getTimeInMillis());
long toOffset = toTimezone.getOffset(calendar.getTimeInMillis());
long convertedTime = calendar.getTimeInMillis() - (fromOffset - toOffset);
//Convert date from one zone to another
/*
$zone_from='Asia/Kolkata';
$zone_to='America/Phoenix';
date_default_timezone_set($zone_from);
$convert_date="2016-02-26 10:35:00";
echo $finalDate=zone_conversion_date($convert_date, $zone_from, $zone_to);
*/
function zone_conversion_date($time, $cur_zone, $req_zone)
{
date_default_timezone_set("GMT");
$gmt = date("Y-m-d H:i:s");
date_default_timezone_set($cur_zone);
$local = date("Y-m-d H:i:s");
date_default_timezone_set($req_zone);
$required = date("Y-m-d H:i:s");
/* return $required; */
$diff1 = (strtotime($gmt) - strtotime($local));
$diff2 = (strtotime($required) - strtotime($gmt));
$date = new DateTime($time);
$date->modify("+$diff1 seconds");
$date->modify("+$diff2 seconds");
return $timestamp = $date->format("Y-m-d H:i:s");
}
Code To Get Berlin Time and Convert it into UTC Time
Calendar sc = Calendar.getInstance(TimeZone.getTimeZone("Europe/Berlin"));
String strt = null;
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
sf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
sc.set(sc.get(Calendar.YEAR),sc.get(Calendar.MONTH), sc.get(Calendar.DATE),sc.get(Calendar.HOUR) , sc.get(Calendar.MINUTE));
strt = sf.format(sc.getTime());
System.out.println("Start :"+strt);

Categories

Resources