Joda-Time strange hour - java

I'm trying to initialise a Joda-Time DateTime object with the hour of 12:00 here is how I do this:
public static final long MINUTE = 60 * 1000;
public static final long HOUR = 60 * MINUTE;
DateTime defaultDate = new DateTime(HOUR * 12);
System.out.print("the hour is: " + defaultDate.getHourOfDay()) // getting 14
Why I am getting 14 and not 12? Maybe Mama didn't teach me how to read clock right?!

You're specifying a number of milliseconds since the Unix epoch, which was midnight UTC.
However, you're implicitly using the system default time zone in your DateTime, and I suspect that at the Unix epoch, your system time zone was UTC+2.
If you want to use a specific time zone, you can pass that in the constructor:
DateTime defaultDate = new DateTime(HOUR * 12, DateTimeZone.UTC);
Also, rather than using your own constants, you could either use DateTimeConstants.MILLIS_PER_HOUR or use java.util.concurrent.TimeUnit for conversions.

java.time
Quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.of(LocalDate.EPOCH, LocalTime.of(12, 0)), ZoneOffset.UTC);
System.out.println(zdt);
}
}
Output:
1970-01-01T12:00Z
ONLINE DEMO
A couple of important notes:
ZonedDateTime#toString removes seconds and fraction-of-second if they are zero. If you want to display them, you can use DateTimeFormatter e.g.
String formatted = zdt.format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH));
The Z in the output is the timezone designator for 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.
What went wrong with your code?
Quoted below the is description of DateTime(long) with my emphasis:
Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z using ISOChronology in the default time zone.
Your place, Israel was at an offset of +02:00 hours in 1970 and therefore the DateTime instance was instantiated with an offset of +02:00 hours.
Demo:
import java.util.concurrent.TimeUnit;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
public class Main {
public static void main(String[] args) {
DateTime defaultDate = new DateTime(TimeUnit.HOURS.toMillis(12), DateTimeZone.UTC);
System.out.println(defaultDate);
}
}
Output:
1970-01-01T12:00:00.000Z
Another thing, which you might have already noticed from the code, is that DO NOT perform calculations yourself if there is already a standard API (e.g. TimeUnit#toMillis) available for the same.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.

Related

Why Java Unix time and Calendar calculate exact time?

I heard that Unix time does not include "Leap Second". And I also heard that Java Calendar API does not include Leap second.
Since 1972, 27 seconds were added as the Leap second. And Unix time began 1970-01-01 00:00:00 (UTC).
So, I thought that there are 27 seconds difference between current UTC time and Unix time.
To clarify my thought, I did some experiment like below. 1614766198 was a Unix time at 2021-03-03 10:10:00 (UTC+0)
import java.util.Calendar;
import java.util.TimeZone;
public class CanendarTest {
public static void main(String[] args) throws InterruptedException {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(1614766198L * 1000);
System.out.println(cal.get(Calendar.YEAR));
System.out.println(cal.get(Calendar.MONTH));
System.out.println(cal.get(Calendar.DAY_OF_MONTH));
System.out.println(cal.get(Calendar.HOUR_OF_DAY));
System.out.println(cal.get(Calendar.MINUTE));
System.out.println(cal.get(Calendar.SECOND));
}
}
The result of above code was
output
2021
2
3
10
9
58
Output seems like "2021-03-03 10:09:58".
So, My Question is that, Why Java Calendar API return 2 second difference from 1970-01-01 00:00:00 (UTC) not 27 second difference?
1614766198 was a Unix time at 2021-03-03 10:10:00 (UTC+0)
This is not correct. The following UNIX command
TZ=UTC date -r 1614766198
outputs
Wed 3 Mar 2021 10:09:58 UTC
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.Instant;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.ofEpochSecond(1614766198);
System.out.println(instant);
}
}
Output:
2021-03-03T10:09:58Z
ONLINE DEMO
An Instant represents an instantaneous point on the timeline in UTC. 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.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.

How to calculate milliseconds with Java as in Ruby?

I can calculate the time in milliseconds with the following Ruby snippet:
$ irb
> require 'date'
=> true
> Date.new(2014,9,5).to_time
=> 2014-09-05 00:00:00 +0200
> Date.new(2014,9,5).to_time.to_i * 1000
=> 1409868000000
1409868000000 is the desired result.
How can I get the same result with Java? I set the time zone to CEST since it seems to be what Ruby works with. So I tried this:
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("CEST"));
calendar.set(2014, 9, 5);
System.out.println("" + calendar.getTimeInMillis());
// Returns: 1412498241422
There are three problems with your current code:
"CEST" isn't a time zone Java recognized. Try Europe/Paris instead, as a European time zone
java.util.Calendar uses 0-based months (yes, it's awful)
You haven't cleared out the time part of the Calendar, so it'll give you the current time of day, on that date
This works:
import java.util.*;
public class Test {
public static void main(String[] args) throws Exception {
TimeZone zone = TimeZone.getTimeZone("Europe/Paris");
Calendar calendar = new GregorianCalendar(zone);
// Month 8 = September in 0-based month numbering
calendar.set(2014, 8, 5, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
System.out.println(calendar.getTimeInMillis());
}
}
If you know the month in advance, you can use the constants instead:
calendar.set(2014, Calendar.SEPTEMBER, 5, 0, 0, 0);
If you can possibly move to using Joda Time or java.time from Java 8, however, those are much cleaner APIs.
For example, in Joda Time:
import org.joda.time.*;
class Test {
public static void main(String[] args) {
DateTimeZone zone = DateTimeZone.forID("Europe/Paris");
// Look ma, a sensible month numbering system!
LocalDate date = new LocalDate(2014, 9, 5);
DateTime zoned = date.toDateTimeAtStartOfDay(zone);
System.out.println(zoned.getMillis());
}
}
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*, released in March 2014.
Also, quoted below is a notice at the Home Page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.ZoneId;
public class Main {
public static void main(String[] args) {
long millis = LocalDate.of(2014, 9, 5)
.atStartOfDay(ZoneId.of("Europe/Paris"))
.toInstant()
.toEpochMilli();
System.out.println(millis);
}
}
Output:
1409868000000
ONLINE DEMO
Avoid using two/three/four letter abbreviation for timezone name. Use the convention Region/City e.g. Europe/Paris. You can get the list of timezone names using ZoneId.getAvailableZoneIds().
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.
You can use System.currentTimeMillis() to get the time in milliseconds since start of epoch.
If you want to translate to the same baseline as Ruby is using, that will be as simple as adding some fixed offset (i.e., use System.currentTimeMillis() + DELTA). You should be able to calculate DELTA by trying it in Ruby and in Java on some fixed date to see what the difference is.
Are you sure that Ruby's calculation isn't locale-dependent, though? It would be odd (not to say barely plausible) if it routinely used CEST.
try
calendar.set(2014, 8, 5, 0, 0, 0);
System.out.println("" + (calendar.getTimeInMillis() / 1000) * 1000);
see http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#set(int,%20int,%20int,%20int,%20int)

How can I convert epoch time to date and time in Java?

I need to convert epoch timestamp to date and time.
I have used the following code to convert but it converts to a wrong date, year and time.
String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
.format(new java.util.Date (1319286637/1000));
Expected output was today’s date at some time, but the result I got was:
01/01/1970 05:51:59
The Date(long) constructor takes milliseconds. You should be multiplying by 1000, not dividing the epoch time you have.
In brief:
Instant.ofEpochSecond( 1_319_286_637L )
2011-10-22T12:30:37Z
Solution using java.time, the modern API:
import java.time.Instant;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.ofEpochSecond(1319286637L);
System.out.println(instant);
}
}
Output:
2011-10-22T12:30:37Z
An Instant represents an instantaneous point on the timeline. The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
You can convert an Instant to other Date-Time types e.g.
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.ofEpochSecond(1319286637);
ZonedDateTime zdt = instant.atZone(ZoneId.of("Asia/Kolkata"));
System.out.println(zdt);
// A custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd/uuuu HH:mm:ss", Locale.ENGLISH);
System.out.println(dtf.format(zdt));
}
}
Output:
2011-10-22T18:00:37+05:30[Asia/Kolkata]
10/22/2011 18:00:37
Learn more about java.time, the modern Date-Time API* from Trail: Date Time.
Note: The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*. However, for any purpose, if you need to convert this object of Instant to an object of java.util.Date, you can do so as follows:
Date date = Date.from(instant);
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.

Date to Day conversion in Java

I am able to convert date to days using the below code.
SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd");
String s1 = sfd.format(dateObj);
String a1 [] = s1.split("-");
int year = Integer.parseInt(a1[0].toString());
int month = Integer.parseInt(a1[1])-1;
int day = Integer.parseInt((a1[2]));
Calendar c1 = Calendar.getInstance();
c1.set(year,month,day);
days = c1.getTime().getTime()/(24*60*60*1000);
The above code works accurately in my system which is windows with timezone GMT +5.30.
However the same code in EST or Pacific timezone adds a day by 1 to final result when the time is 20.00 in the system.
What could be the issue ?
Do we need to set Timezone explicitly in the code ?
input dates does not hold any time stamp ..
is it correct to store in java.util.Date instead of java.sql.Date?
EDIT: As per Alex's comment, it's possible that the problems with the start of your code have blinded me to your real aim.
A Date represents an instant in time. That can fall on different dates depending on the time zone, but how do you want that to affect things? Do you want the number of days since the Unix epoch (which is always UTC) or the number of days since the 1st January 1970 in a particular time zone? Why do you want this "number of days" instead of a representation of a date such as LocalDate? What's the use case here?
EDIT: If you just want to know the number of days since the Unix epoch, you can skip most of this:
days = dateObj.getTime() / (24 * 60 * 60 * 1000);
You shouldn't be going through formatting at all just to get the year / month / day. Just create a Calendar, set the relevant time zone, call setTime with the dateObj you've already got, and then clear the hour/minute/second part of the calendar.
However, you should explicitly specify which time zone you want to consider - a Date represents an instant in time, which will mean different dates in different time zones.
You should also consider using Joda Time which makes all of this simpler and has a specific type for dates (LocalDate). That would also make it easy to find the number of days between the Unix epoch and a particular date without performing the division yourself.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
You can convert the object of java.util.Date to Instant using Date#toInstant and then you can find the number of days from now until this date using ChronoUnit#between.
Demo:
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
// A sample java.util.Date
Date dateObj = GregorianCalendar.from(ZonedDateTime.of(2021, 10, 2, 22, 25, 0, 0, ZoneOffset.UTC)).getTime();
Instant instant = dateObj.toInstant();
// Difference between now and the given java.util.Date
System.out.println(ChronoUnit.DAYS.between(Instant.now(), instant));
}
}
Output:
99
ONLINE DEMO
Note that the above code calculates the number of days between two moments/instants represented in UTC. If you have date-time values local to a particular timezone, you need to specify the corresponding ZoneId.
Demo:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
ZoneId tz = ZoneId.of("Australia/Brisbane");
// A sample java.util.Date representing the local date and time values in Australia/Brisbane
Date dateObj = GregorianCalendar.from(ZonedDateTime.of(2021, 10, 2, 22, 25, 0, 0, tz)).getTime();
// Difference between now in Australia/Brisbane and the given java.util.Date
System.out.println(ChronoUnit.DAYS.between(Instant.now().atZone(tz), dateObj.toInstant().atZone(tz)));
}
}
Output:
98
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.

server time zone java conversion

Ok, so I've pretty much tried everything. I bet it's something really simple but I can't seem to get a hold of it.
The server sends me the time, which is epoch. However when I put this into a date object it seems to automatically pick up the time zone and it adds +3 to the server time. So if the gmt time is 00.00, it says its 03.00.
I also need to add a timezone of my own. Let's say the epoch time is 00.00 again, it should read 10.00 after I add the timezone.
any help would be much appreciated. Thank you
"It seems to add" - I suspect you're using Date.toString() which does indeed use the local time zone. The Date object itself is effectively in UTC though. Use DateFormat to perform the conversion to a string instead, and you can specify which time zone to use. You may also need to use Calendar - it depends what you're trying to do.
(Alternatively, use Joda Time in the first place, which is a better API. It may be a little bulky for your Android project though. I wouldn't be surprised if there were a "Joda Time lite" project around somewhere for precisely this sort of thing...)
EDIT: Quick sample, although it's not entirely clear what you need...
long millis = getMillisFromServer();
Date date = new Date(millis);
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(customTimeZone);
String formatted = format.format(date);
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
long millis = 1316391494L;
Instant instant = Instant.ofEpochMilli(millis);
System.out.println(instant);
// The same instant at a specific timezone
ZonedDateTime zdt = instant.atZone(ZoneId.of("Australia/Brisbane"));
System.out.println(zdt);
}
}
Output:
1970-01-16T05:39:51.494Z
1970-01-16T15:39:51.494+10:00[Australia/Brisbane]
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
What went wrong with your code?
A java.util.Date object simply represents an instant on the timeline — a wrapper around the number of milliseconds since the UNIX epoch (January 1, 1970, 00:00:00 GMT). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
long millis = 1316391494L;
Date date = new Date(millis);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX[zzzz]", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = sdf.format(date);
System.out.println(strDateUtc);
sdf.setTimeZone(TimeZone.getTimeZone("Australia/Brisbane"));
String strDateBrisbane = sdf.format(date);
System.out.println(strDateBrisbane);
}
}
Output:
1970-01-16T05:39:51.494Z[Coordinated Universal Time]
1970-01-16T15:39:51.494+10:00[Australian Eastern Standard Time]
ONLINE DEMO
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. 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 and How to use ThreeTenABP in Android Project.

Categories