2

Given a period such as 3 days, or 5 weeks (a period with only one field type), I want to round a given DateTime to the nearest unit of that period (i.e, ignore the 5 in '5 days'). Examples:

Example 1:

  • Period: 3 days.
  • DateTime: Wednesday 4:26 AM UTC (2013-05-15T04:26:00Z)
  • Rounded DateTime: Wednesday Midnight UTC (2013-05-15T00:00:00Z)

Example 2:

  • Period: 5 weeks.
  • DateTime: Wednesday 4:26 AM UTC (2013-05-15T04:26:00Z)
  • Rounded DateTime: Monday Midnight UTC (2013-05-13T00:00:00Z)

My initial idea was to use Period's DurationFieldType getFieldTypes() method, and for every matching field in a DateTime (below the largest field), set them to zero. However, I don't know how to get the DateTimeFieldTypes from a DateTime and how to compare them to a DurationFieldType.

I would prefer not to do a huge if else approach.

Kevin
  • 4,070
  • 4
  • 45
  • 67

2 Answers2

1

Example bellow is a solution in case you can express period in days (can be modified to weeks, months etc.). Using DateTime Joda Java Library.

Unfortunately with rounding you require I see possible issue. You need to have a starting point in time since when you calculate the periods. In example bellow we calculate periods since 1970/01/01 00:00:00 UTC. Or are you actually asking to get period of 3 days from first day of a month (year) etc? It would make more sense.

Questions you need to ask your self: What will happen on leap days?

Java Method

DateTime roundDays(DateTime dt, int windowDays) {
    Duration p = Duration.standardDays(windowDays);

    long t = dt.getMillis() / p.getMillis() * p.getMillis();
    // Keep TimeZone and round floor to a day
    return new DateTime(t, dt.getZone()).dayOfMonth().roundFloorCopy();
}

Example use:

DateTime dt = new DateTime(1385578964580L, DateTimeZone.UTC);

System.out.println(roundDays(dt, 3));
System.out.println(roundDays(dt.plusDays(2), 3));
System.out.println(roundDays(dt.plusDays(4), 3));
System.out.println(roundDays(dt.plusDays(6), 3));

// Prints data rounded to every 3 days
// 2013-11-26T00:00:00.000Z
// 2013-11-29T00:00:00.000Z
// 2013-11-29T00:00:00.000Z
// 2013-12-02T00:00:00.000Z
vladaman
  • 3,741
  • 2
  • 29
  • 26
0

Too long for comment:

It's not clear what that "rounding" means. To start with, you should deal with LocalDateTimes, not with DateTimes (they are very different things, see my answer here ).

It seems to me you want to set to zero all fields with resolution lower than that of your "period" unit, and then set the next field to a multiple of the given value... is that so? Then, I don't understand your second example (where are the 5 weeks?), and anyway, that would be badly specified: what to do with a period of "40 months" ?

Community
  • 1
  • 1
leonbloy
  • 73,180
  • 20
  • 142
  • 190
  • Yes, I found it hard to express my problem. You understand perfectly. A period of 40 months would be exactly the same as 1 month. I shall investigate using `LocalDateTime`. – Kevin May 16 '13 at 21:24
  • But, again, would you mind explain how you get 2013-05-13 for "5 weeks" ? Are you counting week in year and are you picking the nearest multiple of 5? – leonbloy May 16 '13 at 21:52
  • I only care about the unit 'weeks', and I round down the given `DateTime` to the start of the closest week. Same with 40 months, I want to round down to the closest month (from the given `DateTime`). I have to accept periods such as 40 months, but only the `month` part is needed for this calculation. – Kevin May 16 '13 at 21:57