I'm having trouble with the format method of a SimpleDateFormat object.
The code in question is:
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(date);
Where "date" is a Date object created using a long int from Calendar.getTimeInMillis();
Calendar cal = Calendar.getInstance();
Date date = new Date(cal.getTimeInMillis());
Everything is working fine except the year portion of the string. When I pass the date, the string outputted looks like this:
0044-09-10 05:30:24
The date object that is passed is created from a long integer returned from:
Calendar.getTimeInMillis();
I believe the number returned from this method counts the milliseconds from Jan. 1st. 1970, which I'm thinking is the problem, but even if I add the number of milliseconds in 1970 years (lol, probably the wrong thing to do, but it was worth a shot :P), it still parses as 0044 in the year portion.
I've done numerous google searches and all seem to point simple issues in the string passed to the SimpleDateFormat constructor, so I'm at a loss here.
Any help is greatly appreciated.
Please let me know if any other information is needed and I will do my best to provide it.
Thanks again!
EDIT:
I figured I would explain the context a little more:
A technician will run a call, and on arriving to the site, will mark the call as "Started."
The app will then create a Calendar instance and save the long int returned from Calendar.getTimeInMillis().
When the technician is finished with the call, he/she will mark the call as "Complete." Again, a Calendar instance is created and the long int returned from Calendar.getTimeInMillis() is saved.
This allows easy "call duration" calculation.
Now, when the closing form that the technician uses in the app is used, the long ints saved during the calls is passed to a Date object, which is then passed to a SimpleDateFormat.format() method.
This is where the issue arises. Thanks again, hope this helped.
To calculate duration between date/times, don't rely on subtracting milliseconds, it is highly unreliable.
If you're using Java 8, you should take advantage of the new java.time API, for example...
LocalDateTime dt1 = LocalDateTime.of(2014, 9, 11, 10, 0);
LocalDateTime dt2 = LocalDateTime.of(2014, 9, 11, 12, 0);
Duration duration = Duration.between(dt1, dt2);
System.out.println(duration.toDays());
System.out.println(duration.toHours());
System.out.println(duration.toMinutes());
System.out.println(duration.getSeconds());
Which outputs...
0
2
120
7200
Take a look at Period and Duration for more details.
Alternatively, you could use JodaTime (which the java.time is based off)
The time that the Calendar.getTimeinMillis() returns is the millisecond since the "epoch" time. Consulting the javadoc for Date class, you can find that the "epoch" is January 1, 1970, 00:00:00 GMT. Thus, you code should be fine. I have tested with following code:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class Cal {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
Date date = new Date(cal.getTimeInMillis());
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(date);
System.out.println(date);
}
}
And it gives a correct output:
Thu Sep 11 09:48:30 KST 2014
One think I'd like to mention is the 'call duration' is not a date. If you are trying to convert the result of the subtraction between two long value into a Date object, It will fail because the subtraction will eliminate the since-the-epoch part of the time from the long value. The result of the subtraction is just a millisecond.
Okay, I have solved the issue. It turns out I did not include enough information for everyone to correctly figure out this issue.
In the app, I use two pickers, one for date, and one for time, when saving the date, it saves the date selected, with the time set at 00:00:00 and coverts that to a long int in milliseconds.
using:
Calendar cal = Calendar.getInstance();
cal.set(year, month, day);
When saving the time it saves the time selected using the same method, but when I was calling cal.set() I was setting the year, month, and day, to 0.
i.e.
cal.set(0, 0, 0, hour, minute, second);
changing this statement to
cal.set(1970, 0, 1, hour, minute, second);
fixed the issue. My apologies for wasting everyone's time as this was simply a logical mistake on my part..
I sincerely appreciate all the help provided.
Related
I mentioned that one of the method in the production project work wrong with dates, but i can't just replace it, because it is in production for a long time. I've created a new method, that works correct, but i can't figure out why the first method work wrong.
Old method (that works wrong):
public static Integer getNumberOfDays(Date startDate, Date endDate) {
TimeZone.setDefault((TimeZone.getTimeZone("Europe/Moscow")));
startDate.setHours(00);
startDate.setMinutes(00);
startDate.setSeconds(00);
endDate.setHours(23);
endDate.setMinutes(59);
endDate.setSeconds(59);
Calendar cal1 = Calendar.getInstance();
cal1.setTime(startDate);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(endDate);
Calendar date = (Calendar) cal1.clone();
int daysBetween = 0;
while (date.before(cal2)){
date.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
New method:
public static Integer getNumberOfDaysSecondVersion(Date startDate, Date endDate) {
long difference = startDate.getTime() - endDate.getTime();
float daysBetween = (difference / (1000*60*60*24));
return (int) daysBetween > 0 ? (int) daysBetween : 0;
}
Here is how i call both:
DateFormat formated = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(Calculation.getNumberOfDays(
formated.parse("2018-06-14"),
formated.parse("2018-06-06")
));
System.out.println(Calculation.getNumberOfDaysSecondVersion(
format.parse("2018-06-14"),
format.parse("2018-06-06"))
);
Output:
0
8
Please help.
Your old method is the correct one. When start date is after end date, it returns 0. This is the case in your call.
Your new method subtracts end date from start date, which is wrong, is should be the other way around. I also suspect that it will give surprises across transitions from and to summer time (DST). While Moscow currently doesn’t use summer time, it has done historically, at least until 2010, and may do again if politicians decide so.
That said, you should try if you can avoid the old and long outdated date and time classes DateFormat, SimpleDateFormat, Calendar, Date and TimeZone. Today we have so much better in java.time, the modern Java date and time API. Of course, in legacy code you have old-fashioned Date objects. When writing a new method, I recommend you convert those to the modern LocalDate and use ChronoUnit.DAYS.between().
ChronoUnit.DAYS.between(
LocalDate.parse( "2018-06-14" ) ,
LocalDate.parse( "2018-06-06" )
)
-8
Be aware that when the old method sets the default time zone, it affects all programs running in your JVM and may come as a nasty surprise to other parts of your program and to other programs.
You used a very different algorithm for the two versions.
The old version keeps adding days to the start date until it is after the end date.
The new version subtracts the end date from the start date and divides it by the number of milliseconds there are in a day.
This means that for the first version to work, the start date must be before the end date, and for the second version to work, the start date must be after the end date. The parameters you gave the the first version has the start date after the end date, making it return 0.
To fix this, you can just reverse the two arguments:
System.out.println(getNumberOfDays(
formated.parse("2018-06-06"),
formated.parse("2018-06-14")
));
Or, check which date comes first before calculating the difference between them.
By the way, your first version seems to output one more than your second version. You seem to want a result of 8 days. This means that your first version has an off-by-1 error. You can fix this by subtracting 1 from the counted result.
Remember to always work with java.time whenever you can!
Probably because startDate and endDate's timezones aren't affected by setting the default timezone, so that when you set Calendar times (in Moscow time) based on them, you're converting timezones, possibly turning 00:00:00 into the previous day 21:00:00 or something.
EDIT
Seeing your outputs, it became obvious... you're passing in a start date that is in the future compared to end date. The original method uses a loop that can only count up, while your new method takes the absolute value of the difference.
I have tried all the ways in all the other questions on SO, and I can't get it to work. It is making me want to kill myself.
I have a set of times which are something like "04:00 AM AEST", except the AEST is a glitch, they should be GMT. What I want to do is change them to "04:00 GMT", and then convert them up to the correct AEST times (which in this example would be "14:00 AEST"). I have tried everything, and nothing works. The closest was to manually make a new DateTime using each individual value from the original date, e.g.
DateTime dt = new DateTime(origdate.year, origdate.month, origdate.day, origdate.hour, origdate.minute, origdate.second, timezone.GMT)
But for some reason the results came out four and a half minutes over, which is weird because timezones differ on hours and half hours.
1st Method By following lines you will get GMT time in specified format :
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Date currentLocalTime = cal.getTime();
DateFormat date = new SimpleDateFormat("dd-MM-yyy HH:mm:ss z");
date.setTimeZone(TimeZone.getTimeZone("GMT"));
String gmtTime = date.format(currentLocalTime);
Hence, from GMT you can derive the time of any place.
2nd Method You can get system time of current place in milliseconds by:
Long current_time = System.currentTimeMillis() / 1000L;
Hope it helps.
in Java I'm trying to compare two different hours by converting them to milliseconds if (20:00 > 19:30) // do anything. In millis, it would be if (72000000 > 70200000) // do anything
But the smartphone doesn't do it well. I'm storing the numbers in variables long, as in the class Calendar, the method myCal.getTimeInMillis() returns a long, but it doesn't work.
I have tried changing the data type of the variables from long to double and it does work, so I figure out that those large numbers simply "doesn't fit" in the variable, but then, why the Java Calendar method getTimeInMillis() returns a long?
How does time work in Java Calendar? Thanks in advance.
Edit:
Thank you for your answers and time, I'm sorry for this question because it does work to compare different hours which are stored in long variables. I have tried again and it does work (I don't know why it didn't work before). I'm making an alarm clock app for Android and I want to compare not only two hours (and minutes and seconds), but also day of the week and so on. So I'm going to mark as the solution of this question the answer of #Sufiyan Ghori because I think it can really help me, and I think I'm gonna delete this question because it has no sense.
I'm new here (and in programming in general), so sorry for this silly question.
instead of comparing hours after converting it into milliseconds you can use Date::before or Date::after methods after setting your time into two separate Date objects.
Date date1 = new Date(); // set time for first hour.
Date date2 = new Date(); // set time for second hour.
You can use Calendar to set time for each Date object, like this,
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY,12);
cal.set(Calendar.MINUTE,10);
cal.set(Calendar.SECOND,31);
cal.set(Calendar.MILLISECOND,05);
date1 = cal.getTime(); //set time for first hour
and then use these for comparison,
if(date1.after(date2)){
}
if(date1.before(date2)){
}
and Date::equals,
if(date1.equals(date2)){
}
getTimeInMillis() doesn't return milliseconds passed from the start of the current day, it returns millisecons passed since 01 Jan 1970 00:00:00 GMT.
Take a look at documentation of Calendar class: java.util.Calendar
I have a mobile application where I capture a date/time and send it as miliseconds to a servlet. -For example I capture 12:55 AM in my cellphone and send it to my server-
So, I construct the date from the sent miliseconds and print it with SimpleDateFormat but the time is diferent, it prints 8:55 AM.
I know that the problem is because I use 2 diferent timezones, my question is:
how can I show that time without apply any timezone to show the same time?
Thanks in advance
You need to use Calendar to change the TimeZone but there is no API for that.
// Change a date in another timezone
public static Date changeTimeZone(Date date, TimeZone zone) {
Calendar first = Calendar.getInstance(zone);
first.setTimeInMillis(date.getTime());
Calendar output = Calendar.getInstance();
output.set(Calendar.YEAR, first.get(Calendar.YEAR));
output.set(Calendar.MONTH, first.get(Calendar.MONTH));
output.set(Calendar.DAY_OF_MONTH, first.get(Calendar.DAY_OF_MONTH));
output.set(Calendar.HOUR_OF_DAY, first.get(Calendar.HOUR_OF_DAY));
output.set(Calendar.MINUTE, first.get(Calendar.MINUTE));
output.set(Calendar.SECOND, first.get(Calendar.SECOND));
output.set(Calendar.MILLISECOND, first.get(Calendar.MILLISECOND));
return output.getTime();
}
Link: http://blog.vinodsingh.com/2009/03/date-and-timezone-in-java.html
I think this should work. I haven't extensively tested it.
Calendar and Date objects store their date information in milliseconds in relation to UTC.
(the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC)
This means that Calendar/Date Objects do not store different values for different Time Zones. They always use the same value internally... the format is what normally changes.
Maybe you can use a SimpleDateFormat in your local/default timezone:
SimpleDateFormat sdf = new SimpleDateFormat("S")
Date d = sdf.parse(milliseconds);
You can also try to change the DateFormat's timezone until it matches your expected output.
sdf.setTimeZone(TimeZone.getTimeZone("GMT-8"));
System.out.println(sdf.toString());
sdf.setTimeZone(TimeZone.getTimeZone("GMT-4"));
System.out.println(sdf.toString());
I have a db, that stores dates in OleDateTime format, in GMT timezone. I've implemented a class, extending Date in java to represent that in classic date format. But my class is locale-dependent (I'm in GMT+2). Therefore, it converts the date in the db as date - 2 hours. How do I make it convert the date correctly? I want my class to be locale-independent, always using GMT timezone. Actually, the question is:
class MyOleDateTime extends Date {
static {
Locale.setDefault(WhatGoesHere?)
}
// ... some constructors
// ... some methods
}
Well, it's better to use the Calendar object like suggested in other answers. However, if you really want to set global timezone, you can use TimeZone.setDefault(TimeZone.getTimeZone("UTC")); early in your application code. There is also user.timezone Java system property.
Also (just fun to know), it appears that the only country actually living by GMT/UTC time (without daylight saving changes) is Liberia.
In fact, Date objects per se are always locale- and timezone-independent. Its getTime() method will always return the number of milliseconds passed since January 1, 1970 00:00:00 (not counting leap seconds) in UTC. But if you want to get something else than milliseconds, you have to use Calendar, which is timezone-dependent. But it is the right way to go. You don't use that deprecated methods in Date class, do you?
As Michael Borgwardt has already said, the Java Date object does not know anything about timezones. It's just a wrapper for a number of milliseconds since 01-01-1970 00:00:00 UTC.
You start dealing with timezones only when you for example convert the Date object to a String using a DateFormat. You set the timezone on the DateFormat to specify in which timezone you want to see the Date.
DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String text = df.format(date); // text will contain date represented in UTC
A Date is locale-independent, always using GMT timezone. It's just a wrapper around a millisecond timestamp in GMT (more correctly: UTC).
The only things in Date that are timezone dependant are the deprecated methods like getDay() - that's why they're deprecated. Those use the default time zone. The correct thing to do is to avoid using those deprecated methods - not to set the default timezone to UTC! That could cause problems elsewhere, and you can't prevent other parts of the code from setting the default timezone to something else.
Use a Calendar object:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"),
locale);
Here's a snippet I used to calculate the GMT offset from the Calendar instance and format it. I appreciate all the help I've gotten from this site, its nice to contribute. I hope this helps someone somewhere. Enjoy.
Calendar calInst = Calendar.getInstance();
//calculate the offset to keep calendar instance GMT
int gmtOffsetMilli = calInst.get(Calendar.ZONE_OFFSET);
long gmtOffsetHr = TimeUnit.HOURS.convert(gmtOffsetMilli, TimeUnit.MILLISECONDS);
calInst = Calendar.getInstance(TimeZone.getTimeZone("GMT " + gmtOffsetHr));