简体   繁体   中英

Round down a DateTime based on a given Period using Joda-Time

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 (ie, 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 DateTimeFieldType s from a DateTime and how to compare them to a DurationFieldType .

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

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

Too long for comment:

It's not clear what that "rounding" means. To start with, you should deal with LocalDateTime s, not with DateTime s (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" ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM