Joda持续时间转换为最近的ceil

时间:2017-10-02 23:21:51

标签: java datetime jodatime duration

我正在使用Joda-Time | Domain | Method | URI | Name | Action | Middleware | +--------+-----------+----------------------------------------------------------------+--------------------+----------------------------------------------------------------------------+--------------------+ ... | api | | | POST | api/v1/login/refresh | | App\Http\Controllers\Api\V1\LoginController@postLoginRefresh | api | | | POST | api/v1/logout | | App\Http\Controllers\Api\V1\LoginController@postLogout | api,auth:api | | | POST | api/v1/notes | | App\Http\Controllers\Api\V1\NotesController@postCreate | api,auth:api,admin | | | POST | api/v1/notes/{id} | | App\Http\Controllers\Api\V1\NotesController@postEdit | api,auth:api,admin | | | GET|HEAD | api/v1/notes/{id} | | App\Http\Controllers\Api\V1\NotesController@getNote | api,auth:api,admin | | | DELETE | api/v1/notes/{id} | | App\Http\Controllers\Api\V1\NotesController@deleteNote | api,auth:api,admin | | | PUT | api/v1/public/services/{id} | | App\Http\Controllers\Api\V1\ServicesController@putEdit | api | | | GET|HEAD | api/v1/services | | App\Http\Controllers\Api\V1\ServicesController@getIndex | api,auth:api | | | POST | api/v1/services | | App\Http\Controllers\Api\V1\ServicesController@postCreate | api,auth:api | | | GET|HEAD | api/v1/services/{id} | | App\Http\Controllers\Api\V1\ServicesController@getService | api,auth:api | | | DELETE | api/v1/services/{id} | | App\Http\Controllers\Api\V1\ServicesController@delete | api,auth:api | | | PUT | api/v1/services/{id} | | App\Http\Controllers\Api\V1\ServicesController@putEdit | api,auth:api | | | GET|HEAD | api/v1/services/{id}/cleaners | | App\Http\Controllers\Api\V1\ServicesController@getServiceCleaners | api,auth:api | | | POST | api/v1/services/{id}/cleaners/attach | | App\Http\Controllers\Api\V1\ServicesController@postAttachCleaner | api,auth:api,admin | | | GET|HEAD | api/v1/services/{id}/cleaners/match | | App\Http\Controllers\Api\V1\ServicesController@getMatchingCleaners | api,auth:api,admin | | | PUT | api/v1/services/{id}/confirm | | App\Http\Controllers\Api\V1\ServicesController@putConfirmService | api,auth:api | | | PUT | api/v1/services/{id}/owner | | App\Http\Controllers\Api\V1\ServicesController@putUpdateOwner | api,auth:api | | | GET|HEAD | api/v1/services/{id}/teams | | App\Http\Controllers\Api\V1\ServicesController@getServiceTeams | api,auth:api | | | POST | api/v1/services/{id}/teams/attach | | App\Http\Controllers\Api\V1\ServicesController@postAttachTeam | api,auth:api,admin | | | POST | api/v1/signup/cleaner | | App\Http\Controllers\Api\V1\SignupController@postCleaner | api | | | POST | api/v1/signup/client | | App\Http\Controllers\Api\V1\SignupController@postClient | api | | | POST | api/v1/staffs | | App\Http\Controllers\Api\V1\Users\StaffsController@postCreate | api,auth:api,admin | | | GET|HEAD | api/v1/staffs | | App\Http\Controllers\Api\V1\Users\StaffsController@getIndex | api,auth:api,admin | | | DELETE | api/v1/staffs/{id} | | App\Http\Controllers\Api\V1\Users\StaffsController@destroy | api,auth:api,admin | | | POST | api/v1/staffs/{id} | | App\Http\Controllers\Api\V1\Users\StaffsController@postEdit | api,auth:api,admin | | | GET|HEAD | api/v1/staffs/{id} | | App\Http\Controllers\Api\V1\Users\StaffsController@getShow | api,auth:api,admin | | | PUT | api/v1/staffs/{id}/restore | | App\Http\Controllers\Api\V1\Users\UsersController@restore | api,auth:api,admin | | | GET|HEAD | api/v1/suburbs | | App\Http\Controllers\Api\V1\Support\SuburbsController@getIndex | api | | | GET|HEAD | api/v1/timezones | | App\Http\Controllers\Api\V1\Support\TimezoneController@getIndex | api | | | GET|HEAD | api/v1/user | | Closure | api,auth:api | | | GET|HEAD | api/v1/user/{id}/notes | | App\Http\Controllers\Api\V1\NotesController@getNotes | api,auth:api,admin | | | GET|HEAD | api/v1/users/{user_id}/activities | | App\Http\Controllers\Api\V1\Users\ActivitiesController@getActivities | api,auth:api,admin | | | POST | api/v1/users/{user_id}/stripe/customer | | App\Http\Controllers\Api\V1\StripeController@createCustomer | api | | | GET|HEAD | api/v1/users/{user_id}/stripe/customer | | App\Http\Controllers\Api\V1\StripeController@getCustomer | api | | | GET|HEAD | api/v1/users/{user_id}/stripe/customer/cards | | App\Http\Controllers\Api\V1\StripeController@getCustomerCards | api | | | POST | api/v1/users/{user_id}/stripe/customer/cards | | App\Http\Controllers\Api\V1\StripeController@addCustomerCard | api | | | DELETE | api/v1/users/{user_id}/stripe/customer/cards/{card_id} | | App\Http\Controllers\Api\V1\StripeController@deleteCustomerCard | api | | | PUT | api/v1/users/{user_id}/stripe/customer/cards/{card_id}/default | | App\Http\Controllers\Api\V1\StripeController@setDefaultCard | api | | | GET|HEAD | book | | Closure | web | | | GET|HEAD | checkout | | Closure | web | | | GET|HEAD | cleaner | | Closure | web | | | GET|HEAD | cleaner/{any} | | Closure | web | | | GET|HEAD | invitations/accept/{token} | invitations.accept | App\Http\Controllers\Users\InvitationsController@getAccept | web | | | GET|HEAD | login | | Closure | web | | | GET|HEAD | oauth/authorize | | \Laravel\Passport\Http\Controllers\AuthorizationController@authorize | web,auth | | | POST | oauth/authorize | | \Laravel\Passport\Http\Controllers\ApproveAuthorizationController@approve | web,auth | | | DELETE | oauth/authorize | | \Laravel\Passport\Http\Controllers\DenyAuthorizationController@deny | web,auth | | | POST | oauth/clients | | \Laravel\Passport\Http\Controllers\ClientController@store | web,auth | | | GET|HEAD | oauth/clients | | \Laravel\Passport\Http\Controllers\ClientController@forUser | web,auth | | | PUT | oauth/clients/{client_id} | | \Laravel\Passport\Http\Controllers\ClientController@update | web,auth | | | DELETE | oauth/clients/{client_id} | | \Laravel\Passport\Http\Controllers\ClientController@destroy | web,auth | | | GET|HEAD | oauth/personal-access-tokens | | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@forUser | web,auth | | | POST | oauth/personal-access-tokens | | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@store | web,auth | | | DELETE | oauth/personal-access-tokens/{token_id} | | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@destroy | web,auth | | | GET|HEAD | oauth/scopes | | \Laravel\Passport\Http\Controllers\ScopeController@all | web,auth | | | POST | oauth/token | | \Laravel\Passport\Http\Controllers\AccessTokenController@issueToken | throttle | | | POST | oauth/token/refresh | | \Laravel\Passport\Http\Controllers\TransientTokenController@refresh | web,auth | | | GET|HEAD | oauth/tokens | | \Laravel\Passport\Http\Controllers\AuthorizedAccessTokenController@forUser | web,auth | | | DELETE | oauth/tokens/{token_id} ... 来获取两个Duration之间的持续时间:

DateTime

我想按照以下规则进行转换:

DateTime startTimeDate = new DateTime(startTimeDateInLong, DateTimeZone.UTC);
DateTime endTimeDate = new DateTime(endTimeDateInLong, DateTimeZone.UTC);

Duration duration = new Duration(startTimeDate, endTimeDate);

我正在使用0-60 seconds --> 1 minute .. 1.5 - 1 hour --> 1 hour 1.6 hour - 2 hour --> 2 hour ,但是96分钟它会提供1小时而不是2小时。

2 个答案:

答案 0 :(得分:1)

Duration类不会按您希望的方式对值进行舍入。即使您获得1小时59分59秒999毫秒的持续时间,toStandardHours()也会返回1

要获得所需的结果,必须以秒为单位获取总数,然后相应地操作此值。您可以使用java.math.BigDecimal类和java.math.RoundingMode来控制值的舍入方式:

// 96-minutes duration
Duration duration = new Duration(96 * 60 * 1000);
long secs = duration.toStandardSeconds().getSeconds();
if (secs >= 3600) { // more than 1 hour
    BigDecimal secondsPerHour = new BigDecimal(3600);
    int hours = new BigDecimal(secs).divide(secondsPerHour, RoundingMode.HALF_DOWN).intValue();

    System.out.println(hours + " hour" + (hours > 1 ? "s" : "")); // 2 hours
} else {
    int mins;
    if (secs == 0) { // round zero seconds to 1 minute
        mins = 1;
    } else {
        // always round up (1-59 seconds = 1 minute)
        BigDecimal secondsPerMin = new BigDecimal(60);
        mins = new BigDecimal(secs).divide(secondsPerMin, RoundingMode.UP).intValue();
    }
    System.out.println(mins + " minute" + (mins > 1 ? "s" : ""));
}

这将打印2 hours持续96分钟,1 minute持续时间介于0到60秒之间,依此类推。

要获得以秒为单位的差异,您还可以使用org.joda.time.Seconds类:

long secs = Seconds.secondsBetween(startTimeDate, endTimeDate).getSeconds();

Java新日期/时间API

Joda-Time处于维护模式,正在被新的API取代,因此我不建议使用它来启动新项目。即使在joda's website中它也说:“请注意,Joda-Time被认为是一个很大程度上”完成“的项目。没有计划大的增强。如果使用Java SE 8,请迁移到java.time(JSR) -310)。“即可。

如果您不能(或不想)从Joda-Time迁移到新API,则可以忽略此部分。

如果您使用的是 Java 8 ,请考虑使用new java.time API。它更容易,less bugged and less error-prone than the old APIs

如果您使用的是 Java 6或7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ,您还需要ThreeTenABP(更多关于如何使用它here)。

以下代码适用于两者。 唯一的区别是包名称(在Java 8中为java.time,在ThreeTen Backport(或Android的ThreeTenABP)中为org.threeten.bp),但类和方法名称是相同的

首先,要从epoch毫秒值获取相应的瞬间,您可以使用Instant类(无需将时区设置为UTC,因为Instant表示UTC时刻)。然后,要计算差异,您可以使用Duration

long startTimeDateInLong = // long millis value
long endTimeDateInLong = // long millis value

// get the corresponding Instant
Instant start = Instant.ofEpochMilli(startTimeDateInLong);
Instant end = Instant.ofEpochMilli(endTimeDateInLong);

// get the difference in seconds
Duration duration = Duration.between(start, end);
long secs = duration.getSeconds();

// perform the same calculations as above (with BigDecimal)

你也可以用ChronoUnit来获得差异:

long secs = ChronoUnit.SECONDS.between(start, end);

答案 1 :(得分:0)

我能找到的唯一方法就是先把时间缩小到较小的单位,然后转换成欲望的单位并围绕它。因此,例如,对于所提到的用例,获得舍入分钟的方法将是这样的:

public Minutes getRoundedMinutes(DateTime dateTime1, DateTime dateTime2) {
    return Minutes.minutes(
            (int) round((double) secondsBetween(dateTime1, dateTime2).getSeconds() / Minutes.ONE.toStandardSeconds().getSeconds()));
}

@Test
public void should_round_minutes() throws Exception {
    DateTime dateTime1 = new DateTime(2018, 1, 1, 1, 0, 0);
    DateTime dateTime2 = new DateTime(2018, 1, 1, 1, 0, 29);
    DateTime dateTime3 = new DateTime(2018, 1, 1, 1, 0, 30);
    DateTime dateTime4 = new DateTime(2018, 1, 1, 1, 1, 1);
    DateTime dateTime5 = new DateTime(2018, 1, 1, 1, 1, 31);

    assertThat(getRoundedMinutes(dateTime1, dateTime2).getMinutes()).isEqualTo(0);
    assertThat(getRoundedMinutes(dateTime1, dateTime3).getMinutes()).isEqualTo(1);
    assertThat(getRoundedMinutes(dateTime1, dateTime4).getMinutes()).isEqualTo(1);
    assertThat(getRoundedMinutes(dateTime1, dateTime5).getMinutes()).isEqualTo(2);
}