Question

Say I have an algorithm in Java where I want to do something on a monthly basis based off the time associated with each object.

So for example, if Object a has time long t, and t is in milliseconds since the epoch, how would I find out that t is a time in 03/2014?

As a secondary question, how can I iterate over months backwards in time - so if I'm starting on May 1, 2014, how can I accurately go back to April, March, Feb, etc, without worrying about the whole problem of having 28 - 31 days in a month? I was considering using the Calendar class, but wasn't sure if I can just update the MONTH variable and have it give me a correct millisecond value. Like, what if it's March 31, and I update the month to February, and then suddenly it thinks it's Feb 31?

Was it helpful?

Solution

The easiest way to do this is to use the java.util.Calendar class as you mention in your question. You can easily get an instance by using

//use whatever time zone your milliseconds originiate from
//there is another getter that takes a Locale, which may be useful depending on your context
Calander c = Calendar.getInstance(TimeZone.getDefault());

You can then set the time using

c.setTimeInMillis(t);

In order to find out when this was, you can print out the result using a DateFormat object

DateFormat df = DateFormat.getInstance(DateFormat.SHORT);
System.out.println(df.format(c.getTime());

To move through the months (or any other unit of time), you would "add" to the calendar using the month field:

c.add(Calendar.MONTH, -2);

The good news is that you can use the add() method for any other time unit and the Calendar class will take care of properly adjusting the date as needed, in the way you expect (i.e., the culturally appropriate way defined by the Locale of the Calendar).

Lastly, you can get this turned back into milliseconds by using

long newTime = c.getTimeInMillis();

OTHER TIPS

I think your first question has been answered here java convert milliseconds to time format

You only need to create a new Date object and pass the timestamp to the constructor. Then you can format the date as desired.

Using the Java 8 API in java.time you could do the following:

import java.time.Instant;
import java.time.Month;
import java.time.MonthDay;
import java.time.OffsetDateTime;

public static void main(String[] args) {
    long ms_since_epoch = 1_500_000_000_000L;
    Instant instant = Instant.ofEpochMilli(ms_since_epoch);

    // convert milliseconds in UTC to date
    OffsetDateTime dateUTC = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);

    // convert milliseconds in EST (UTC-0500) to date
    OffsetDateTime dateEST = OffsetDateTime.ofInstant(instant, ZoneOffset.ofHours(-5));
    // note: this is 2017-07-14 at 2:40

    // create a MonthDay from the date in EST
    MonthDay monthDay = MonthDay.of(dateEST.getMonth(), dateEST.getDayOfMonth());
    // note: this is 2017-07-13 at 21:40

    // loop over the next six months, after monthDay from dateEST
    MonthDay md = monthDay;
    for (int i = 0; i < 6; ++i) {
        md = md.with(md.getMonth().plus(1));
        System.out.println(md);
        // prints 08-13 through 01-14 (August 2013 through January 2014)
    }

    // loop over the previous six months, including this month
    md = monthDay;
    for (int i = 0; i < 6; ++i) {
        System.out.println(md);
        md = md.with(md.getMonth().minus(1));
        // prints 07-13 through 02-13 (July 2013 through February 2013)
    }
}

Note that MonthDay is immutable, so calling md.with(otherMonth) returns a new instance with the month changed, and it only represents a month and a day, not a complete date with year, time, and time zone. Note also how converting the timestamp yields a different date and time depending on the time zone, which will also be true with Calendar.

Which Epoch? Which Time Zone?

Your question ignores crucial issues:

  • Milliseconds since what epoch? There are many epochs. In all 3 common Java-based libraries (java.util.Date/Calendar, Joda-Time, java.time), the epoch is the first moment of 1970 in UTC (ignoring leap seconds).
  • What time zone is represented by that count of milliseconds? UTC or some local time zone?

Joda-Time

Here is some example code using the Joda-Time 2.3 library.

Generate some milliseconds. Notice the use of long not int.

long millis = new DateTime( 2014, 1, 2, 3, 4, 5, DateTimeZone.UTC ).getMillis();

Instantiate a DateTime by passing the milliseconds to the constructor. Specify the time zone by which to interprent those milliseconds.

DateTime dateTime = new DateTime( millis, DateTimeZone.UTC );

Define the beginning and ending of a month. The Interval class represents a span of time such as this.

DateTime firstOfMarchInParis = new DateTime( 2014, 3, 1, 0, 0, 0 , DateTimeZone.forID( "Europe/Paris" ) ).withTimeAtStartOfDay();
Interval marchInParis = new Interval( firstOfMarchInParis, firstOfMarchInParis.plusMonths( 1) );

Comparison is best performed in date-time work by using the "Half-Open" approach. "Half-Open" is a math term, meaning the beginning is inclusive and the ending is exclusive. So the interval above is defined as "from the first moment of the first of March and going up to, but not including, the first moment of the first of the following month". Joda-Time uses this "half-open" approach.

boolean isTargetInMarchInParis = marchInParis.contains( dateTime );

As for your secondary question about adding/subtracting months, notice that the Joda-Time DateTime methods plusMonths and minusMonths give the behavior you want.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top