strip time from timestamp - java

Why cannot I clear the time from a timestamp this way:
one day == 24 * 3600 * 1000 == 86400000 milliseconds.
long ms = new Date().getTime(); //Mon Sep 03 10:06:59 CEST 2012
Date date = new Date(ms - (ms % 86400000));
how come this is Mon Sep 03 02:00:00 CEST 2012 instead of Mon Sep 03 00:00:00 CEST 2012?

Why cannot I clear time from timestamm this way
You're correctly clearing the time part in UTC. The millisecond values in Date are always relative to January 1st 1970 midnight in UTC. However, you're not displaying it in UTC, because of the way Date.toString() works (it always uses the system local time zone). Note that a Date itself has no concept of a time zone. It's just a number of milliseconds since January 1st 1970 midnight UTC.
The concept of "clearing a time from a timestamp" doesn't really make sense without specifying which time zone you're talking about, as the same timestamp will have different times of day (and even dates) in different time zones.
To be honest, I would suggest using Joda Time for any significant date/time work. Then you can create a LocalDate which is obviously meant to represent "just a date" - and the translation from a Date (or Instant) to a LocalDate will make it easy for you to specify whichever time zone you want to use.

I actually want to compare it to another date not taking into account time of day
To compare dates I suggest using JodaTime which supports this functionality with LocalDate
LocalDate date1 = new LocalDate(); // just the date without a time or time zone
LocalDate date2 = ....
if (date1.compareTo(date2) <=> 0)
Note: this will construct timezone-less LocalDates which is appropriate for the default timezone. As long as you are only talking about the timezone where the default timezone for the machine has been set, this is fine. e.g. say you have a timezone of CEST then this is fine for most of Europe.
Using the built in time functions you can do something like
public static int compareDatesInTimeZone(Date d1, Date d2, TimeZone tz) {
long t1 = d1.getTime();
t1 += tz.getOffset(t1);
long t2 = d2.getTime();
t2 += tz.getOffset(t2);
return Double.compare(t1 / 86400000, t2 / 86400000);
}

Try this...
Calendar c = Calendar.getInstance();
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
String strDate = df.format(c.getTime()));
Now this way you can have the another date, and then compare it....as they are now in String format.

Related

Dateformat converting IST to GMT

Problem in converting IST to GMT.
DateFormat df = new SimpleDateFormat("HH:mm:ss z");
String input = "05:30:00 IST";
Date d = df.parse(input);
Calendar c = Calendar.getInstance();
c.setTime(d);
System.out.println(c.getTime());
getting Thu Jan 01 03:30:00 GMT 1970 as output instead of Thu Jan 01 00:00:00 GMT 1970
You should be wary of using three-letter abbreviations of timezones because they are ambiguous. In this case, IST could refer to:
Indian Standard Time (UTC+0530)
Israel Standard Time (UTC+02)
Irish Standard Time (UTC+01)
Wikipedia lists some common timezone abbreviations; examples of other ambiguous common abbreviations are:
AM(S)T
AST
BST
CDT
CST
ECT
FKST
GST
MST
It is better to use either a UTC offset (e.g. +0530 for Indian Standard Time) or a uniquely-defined timezone identifier (e.g. Asia/Calcutta)
There are a number of things wrong with what you seem to be trying to do here.
You are trying to use a java.util.Date object to contain just a time-of-day (hours, minutes, seconds). A java.util.Date object is not suitable for that purpose. A java.util.Date object is really a timestamp - it represents an "absolute" moment in time, counted as a number of milliseconds since 01-01-1970, 00:00:00 GMT.
A java.util.Date object does not contain timezone information. You cannot convert a Date object from one timezone to another timezone, because the Date object simply does not contain information about a timezone.
Converting a time-of-day from one timezone to another cannot be done if you only know the hours, minutes and seconds. The result also depends on the date (year, month, day) - the results can be influenced by daylight savings transitions. So it's not possible to convert a time-of-day from one timezone to another if you don't know the date.
If you use the Java 8 java.time API, then it's easy; use ZonedDateTime, which does contain information about the timezone.
// Assuming that with "IST" you mean India Standard Time
ZonedDateTime input = ZonedDateTime.of(2015, 3, 23, 5, 30, 0, 0, ZoneId.of("Asia/Calcutta"));
System.out.println(input);
ZonedDateTime output = input.withZoneSameInstant(ZoneId.of("GMT"));
System.out.println(output);
If you want to use the old java.util.Date and java.util.Calendar API, then you set the timezone on the DateFormat object that you use to display the date - not on the Date object itself:
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
cal.set(2015, Calendar.MARCH, 23, 5, 30, 0);
Date input = cal.getTime();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
System.out.println(df.format(input));
df.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(df.format(input));

java.util.Date get milliseconds

I have done the following:
String standardRange = "00:01:01";
SimpleDateFormat rangeFormatter = new SimpleDateFormat("hh:mm:ss");
Date range = rangeFormatter.parse(standardRange);
Now:
range.getTime();
.. I get the output of -3539000 and not 61,000
I'm not sure what I'm doing wrong; when debugging, cdate exists, the attribute contains a fraction, which contains the value 61,000, which is what I want.
The reason you're seeing this is that the date you're creating is actually in the past of the date epoch, not 1m1s after it:
String standartRange = "00:01:01";
SimpleDateFormat rangeFormatter = new SimpleDateFormat("hh:mm:ss");
Date range = rangeFormatter.parse(standartRange);
System.out.println(new Date(0L));
System.out.println(new Date(0L).getTime());
System.out.println(range);
System.out.println(range.getTime());
and its output;
Thu Jan 01 01:00:00 GMT 1970
0
Thu Jan 01 00:01:01 GMT 1970
-3539000
The epoch date is incorrect here - it should be 00:00:00, but due to a historical bug where BST/GMT changed dates and timezone cant keep track. It seems that Sun/Oracle consider this a historical "inaccuracy".
Check out the bug report - its describes the problem more fully.
From your language (German) this may not be directly due to this BST issue, but its almost certainly related.
Java Date is not designed to calculate the duration of a given time period.
The getTime() call returns the numbers of milliseconds since January 1, 1970, 00:00:00 GMT. In your case you are actually ending up with a date that comes before that epoch (thus the negative number). When I run your code I get 21661000. (See the answer from Sean Landsman as I believe he has hit on why you get the negative results...hint: my number is exactly 6 hours off of GMT or 21600000ms)
Joda-Time is a library that is well suited to solving your underlying problem.
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendHours()
.appendSeparator(":")
.appendMinutes()
.appendSeparator(":")
.appendSeconds()
.toFormatter();
Period period = formatter.parsePeriod("00:01:01");
assert period.toStandardDuration().getMillis() == 61000
According to the JavaDoc, getTime():
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.
You want the number of milliseconds in one minute and one second.
(60*minutes+seconds)*1000
It really doesn't need to come from a Date object.
If you need to compute the time in milliseconds for some interval, maybe use the joda time library, or get the day, hour, minute, second and millisecond components out of your date object and compute the value by hand.
To get what you want, you should compare between the time you want and origin of the time. using the below code:
String standardRange = "00:01:01";
SimpleDateFormat rangeFormatter = new SimpleDateFormat("HH:mm:ss");
Date range = rangeFormatter.parse(standardRange);
Date range2 = rangeFormatter.parse("00:00:00");
System.out.println(range.getTime() - range2.getTime());
hh:mm:ss stands for 12-hour time, which always stands for "time point", not "time interval". So surely, time zone will effect the value. However, in GMT +0 the value equals to which represents "time interval".
All you just need is:
rangeFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
Try it!
Try:
Date range1 = rangeFormatter.parse("00:01:01");
Date range2 = rangeFormatter.parse("00:00:00");
System.out.println(range1.getTime() - range2.getTime());

Java SimpleDateFormat: an hour wrong

I don't need a whole story to clarify my question, so I'll just show the code (which is a mere example). How come there is a difference in my result?
Code
long millis = 2305293L;
System.out.println(
millis + "ms = " +
(millis / 1000) + "s = " +
(millis / 1000 / 60) + "m");
System.out.println(
new SimpleDateFormat("HH:mm:ss").
format(
new Date(millis)
)
);
Output
2305293ms = 2305s = 38m
01:38:25
If you are in London, or Paris, the timezone was GMT+1 on 1 Jan 1970.
For reasons #ARC explains in the comments, the UK used GMT+1 or UTC+1 from 18 Feb 1968 to 31 Oct 1971
is it possible for me to convert a long without any timezones interfering?
Set the TimeZone to be GMT.
long millis = 2305293L;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(sdf.format(new Date(millis)));
prints
00:38:25.293
Try this :
System.out.println(new java.util.Date (0));
you will see it begins at 01:00:00, hence the difference of one hour.
The other answers are correct and were good answers when the question was asked in 2013. Today we should no longer use Date nor SimpleDateFormat, so I would like to show you a couple of modern code snippets instead. The correct way to format your (in this case) 2 305 293 milliseconds depends on what they represent. I am presenting three options for three different situations.
Formatting a number of milliseconds since the epoch
You need to decide in which time zone you want to interpret your point in time. For example:
long millis = 2_305_293L;
DateTimeFormatter formatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.ENGLISH);
ZonedDateTime dateTime = Instant.ofEpochMilli(millis)
.atZone(ZoneId.of("America/Coral_Harbour"));
String formattedTime = dateTime.format(formatter);
System.out.println(formattedTime);
December 31, 1969 at 7:38:25 PM EST
Since at the epoch Coral Harbor was at UTC offset -05:00, we get a time near the end of 1969. If you want the time in UTC (since the epoch is defined in UTC; in other words, if you want 00:38:25), it’s a bit different:
DateTimeFormatter formatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(Locale.ENGLISH);
OffsetDateTime dateTime = Instant.ofEpochMilli(millis)
.atOffset(ZoneOffset.UTC);
Jan 1, 1970, 12:38:25 AM
In addition to time zone you may vary the language through the locale and the length of the format through the format style (full, long, medium, short). If you want the time of day without the date, use ofLocalizedTime instead of ofLocalizedDateTime.
Formatting a millisecond of day
Assuming your milliseconds are since 0:00 (“midnight”) in whatever time zone:
LocalTime time = LocalTime.MIN.with(ChronoField.MILLI_OF_DAY, millis);
System.out.println(time);
00:38:25.293
If this format is satisfactory, you don’t need any explicit formatter. If not, you may use a DateTimeFormatter.
Formatting a duration, an amount of time
An amount of time is a completely different thing from a time and is handled as a Duration object. There is no direct support for formatting it, but since Java 9 it’s not so hard (when you know how):
Duration amountOfTime = Duration.ofMillis(millis);
String formattedTime = String.format("%02d:%02d:%02d",amountOfTime.toHours(),
amountOfTime.toMinutesPart(), amountOfTime.toSecondsPart());
System.out.println(formattedTime);
00:38:25
Link
Oracle tutorial: Date Time explaining how to use java.time.

Converting Long to Date in Java returns 1970

I have list with long values (for example: 1220227200, 1220832000, 1221436800...) which I downloaded from web service. I must convert it to Dates. Unfortunately this way, for example:
Date d = new Date(1220227200);
returns 1 Jan 1970. Anyone know another way to convert it correctly?
The Date constructor (click the link!) accepts the time as long in milliseconds, not seconds. You need to multiply it by 1000 and make sure that you supply it as long.
Date d = new Date(1220227200L * 1000);
This shows here
Sun Aug 31 20:00:00 GMT-04:00 2008
tl;dr
java.time.Instant // Represent a moment as seen in UTC. Internally, a count of nanoseconds since 1970-01-01T00:00Z.
.ofEpochSecond( 1_220_227_200L ) // Pass a count of whole seconds since the same epoch reference of 1970-01-01T00:00Z.
Know Your Data
People use various precisions in tracking time as a number since an epoch. So when you obtain some numbers to be interpreted as a count since an epoch, you must determine:
What epoch?Many epochs dates have been used in various systems. Commonly used is POSIX/Unix time, where the epoch is the first moment of 1970 in UTC. But you should not assume this epoch.
What precision?Are we talking seconds, milliseconds, microseconds, or nanoseconds since the epoch?
What time zone?Usually a count since epoch is in UTC/GMT time zone, that is, has no time zone offset at all. But sometimes, when involving inexperienced or date-time ignorant programmers, there may be an implied time zone.
In your case, as others noted, you seem to have been given seconds since the Unix epoch. But you are passing those seconds to a constructor that expects milliseconds. So the solution is to multiply by 1,000.
Lessons learned:
Determine, don't assume, the meaning of received data.
Read the doc.
Your Data
Your data seems to be in whole seconds. If we assume an epoch of the beginning of 1970, and if we assume UTC time zone, then 1,220,227,200 is the first moment of the first day of September 2008.
Joda-Time
The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use instead either the Joda-Time library or the new java.time package bundled in Java 8 (and inspired by Joda-Time).
Note that unlike j.u.Date, a DateTime in Joda-Time truly knows its own assigned time zone. So in the example Joda-Time 2.4 code seen below, note that we first parse the milliseconds using the default assumption of UTC. Then, secondly, we assign a time zone of Paris to adjust. Same moment in the timeline of the Universe, but different wall-clock time. For demonstration, we adjust again, to UTC. Almost always better to explicitly specify your desired/expected time zone rather than rely on an implicit default (often the cause of trouble in date-time work).
We need milliseconds to construct a DateTime. So take your input of seconds, and multiply by a thousand. Note that the result must be a 64-bit long as we would overflow a 32-bit int.
long input = 1_220_227_200L; // Note the "L" appended to long integer literals.
long milliseconds = ( input * 1_000L ); // Use a "long", not the usual "int". Note the appended "L".
Feed that count of milliseconds to constructor. That particular constructor assumes the count is from the Unix epoch of 1970. So adjust time zone as desired, after construction.
Use proper time zone names, a combination of continent and city/region. Never use 3 or 4 letter codes such as EST as they are neither standardized not unique.
DateTime dateTimeParis = new DateTime( milliseconds ).withZone( DateTimeZone.forID( "Europe/Paris" ) );
For demonstration, adjust the time zone again.
DateTime dateTimeUtc = dateTimeParis.withZone( DateTimeZone.UTC );
DateTime dateTimeMontréal = dateTimeParis.withZone( DateTimeZone.forID( "America/Montreal" ) );
Dump to console. Note how the date is different in Montréal, as the new day has begun in Europe but not yet in America.
System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeUTC: " + dateTimeUtc );
System.out.println( "dateTimeMontréal: " + dateTimeMontréal );
When run.
dateTimeParis: 2008-09-01T02:00:00.000+02:00
dateTimeUTC: 2008-09-01T00:00:00.000Z
dateTimeMontréal: 2008-08-31T20:00:00.000-04:00
java.time
The makers of Joda-Time have asked us to migrate to its replacement, the java.time framework as soon as is convenient. While Joda-Time continues to be actively supported, all future development will be done on the java.time classes and their extensions in the ThreeTen-Extra project.
The java-time framework is defined by JSR 310 and built into Java 8 and later. The java.time classes have been back-ported to Java 6 & 7 on the ThreeTen-Backport project and to Android in the ThreeTenABP project.
An Instant is a moment on the timeline in UTC with a resolution of nanoseconds. Its epoch is the first moment of 1970 in UTC.
Instant instant = Instant.ofEpochSecond( 1_220_227_200L );
Apply an offset-from-UTC ZoneOffset to get an OffsetDateTime.
Better yet, if known, apply a time zone ZoneId to get a ZonedDateTime.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
It looks like your longs are seconds, and not milliseconds. Date constructor takes time as millis, so
Date d = new Date(timeInSeconds * 1000);
Only set the time in mills on Calendar object
Calendar c = Calendar.getInstance();
c.setTimeInMillis(1385355600000l);
System.out.println(c.get(Calendar.YEAR));
System.out.println(c.get(Calendar.MONTH));
System.out.println(c.get(Calendar.DAY_OF_MONTH));
// get Date
System.out.println(c.getTime());
Those are probably timestamps in seconds and not in milliseconds which is required for the java new Date(long) constructor. Just multiply them by 1000 and you should be allright.
The long values, most likely, correspond to Epoch timestamps, and the values are:
1220227200 = Mon, 01 Sep 2008 00:00:00 GMT
1220832000 = Mon, 08 Sep 2008 00:00:00 GMT
1221436800 = Mon, 15 Sep 2008 00:00:00 GMT
One can convert these long values to java.util.Date, taking into account the fact java.util.Date uses millisecs – as previously hinted, but with some flaw - like this:
// note: enforcing long literals (L), without it the values would just be wrong.
Date date = new Date(1220227200L * 1000L);
Now, to display the date correctly, one can use java.text.DateFormat as illustrated hereafter:
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Wrong date time value: " + date);
System.out.println("Correct date time value: " + df.format(date));
Below are the results of displaying the converted long value to java.util.Date without
using and using the DateFormat:
Date wrong (off by 2 hours): Mon Sep 01 02:00:00 CEST 2008
Correct date : Monday, 1 September 2008 00:00:00 o'clock UTC
Try this:
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1220227200 * 1000);
System.out.println(cal.getTime());
Try this with adjusting the date format.
long longtime = 1212580300;
SimpleDateFormat dateFormat = new SimpleDateFormat("MMddyyHHmm");
Date date = (Date) dateFormat.parseObject(longtime + "");
System.out.println(date);
Note: Check for 24 hours or 12 hours cycle.
1220227200 corresponds to Jan 15 1980 (and indeed new Date(1220227200).toString() returns "Thu Jan 15 03:57:07 CET 1970"). If you pass a long value to a date, that is before 01/01/1970 it will in fact return a date of 01/01/1970. Make sure that your values are not in this situation (lower than 82800000).
New Date(number) returns a date that's number milliseconds after 1 Jan 1970. Odds are you date format isn't showing hours, minutes, and seconds for you to see that it's just a little bit after 1 Jan 1970.
You need to parse the date according to the correct parsing routing. I don't know what a 1220227200 is, but if it's seconds after 1 JAN 1970, then multiply it to yield milliseconds. If it is not, then convert it in some manner to milliseconds after 1970 (if you want to continue to use java.util.Date).
Works for me. You probably want to multiplz it with 1000, since what you get are the seconds from 1970 and you have to pass the milliseconds from jan 1 1970
Because 1220227200 ms = 338,952 hours.
java.util.Date has constructor new Date(Long milliseconds) - Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
So, in your case just remember 1 sec = 1000 millisec

Is it possible to create a Calendar object like Tue Mar 03 13:43:00 (without time zone)?

I have a requirement of sending the calendar object with time zone, like Tue Mar 03 13:43:00. I know that Calendar object always return with Tue Mar 03 13:43:00 CST 2009, so how can I create it without the time zone?
You can use the DateFormat class (more specifically the SimpleDateFormat concrete subclass) to format the date however you want. Here is an example:
Calendar cal = Calendar.getInstance();
DateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss");
String dateString = format.format(cal.getTime()));
Prints:
Fri Mar 06 15:50:26
It's not possible to have a Calendar object without a TimeZone. Really, that doesn't make any sense - Calendar seeks to represent "a specific instant in time" - how can you represent an instance in time without knowing what TimeZone the time you are representing is in?
So, there's a few things to consider:
You say you need to pass this Calendar to some other component - does that API care what TimeZone the Calendars are in? Will that API ignore the TimeZone setting, use it to calculate a time difference against it's own local timezone, etc.?
Are you aware that you can easily change the TimeZone of a Calendar instance?
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getDefault()); // returns default TimeZone for your system
cal.setTimeZone(TimeZone.getTimeZone("EST")); // Eastern Standard Time
cal.setTimeZone(TimeZone.getTimeZone("Asia/Kolkota"); // UTC+5:30
Javadocs on Calendar, TimeZone.
You can use a simple Date object using;
Date d = new Date();
Date d2 = calendar.getTime();
Or the even simpler, time in milli-seconds.
long time = System.currentTimeMillis();
To avoid confusion over time zones, I suggest storing and setting all date/times as a standard time zone, such as GMT+0 and then converting the time for display etc as required.
Upon rereading your question and your comments on my other answer, it sounds like the problem is that you want the result to be a Calendar object, not a String. So it isn't a question of formatting the String representation of the Calendar.
In this case, what you are asking is technically impossible: all implementations of the Calendar class exist to represent an internal time, which is stored as the number of milliseconds since the Unix epoch (Jan 1 1970 00:00 GMT). The time "5:00 am" in Boston is different from "5:00 am" in Seattle--they have different internal timestamps.
Your best bet would be to use the same time zone everywhere, and probably GMT makes the most sense for that purpose:
cal.setTimeZone(TimeZone.getTimeZone("GMT+0000"));

Categories