我有一个带有number和timeUnit的类
import Prelude hiding (product)
import Data.Functor.Foldable
product :: ListF Int Int -> Int
product Nil = 1
product (Cons a b) = a * b
countDown :: Int -> ListF Int Int
countDown 0 = Nil
countDown n = Cons n (n - 1)
fact :: Int -> Int
fact = hylo product countDown
TimeUnit是一个枚举
public static class Time {
private int number;
private Unit unit;
}
所以时间的可能值是
public enum Unit {
days,
months,
years;
}
我想减去今天起的时间,但现在确定如何实现。
这里是一个例子,
如果TimePeriod为30天,则resultDate = Instant.now()-30天。
如果TimePeriod为15个月,则resultDate = Instant.now()-450 天
如果TimePeriod为2年,则resultDate = Instant.now()-730天
答案 0 :(得分:2)
您可以这样做:
ServiceBusTrigger
*)在出现数字溢出的情况下使用multiplyExact()
失败。
测试
public enum TimeUnit {
DAYS(1),
MONTHS(30),
YEARS(365);
private final int days;
private TimeUnit(int days) {
this.days = days;
}
public <R extends Temporal> R addTo(R temporal, long amount) {
return ChronoUnit.DAYS.addTo(temporal, Math.multiplyExact(amount, this.days));
}
}
样本输出
System.out.println(Instant.now());
System.out.println(TimeUnit.DAYS.addTo(Instant.now(), -30));
System.out.println(TimeUnit.MONTHS.addTo(Instant.now(), -15));
System.out.println(TimeUnit.YEARS.addTo(Instant.now(), -2));
您的示例输出将2019-05-06T21:04:50.781231200Z
2019-04-06T21:04:50.781231200Z
2018-02-10T21:04:50.781231200Z
2017-05-06T21:04:50.781231200Z
替换为Instant
LocalDate
答案 1 :(得分:2)
向您的TimePeriod
类添加方法
@AllArgsConstructor
@Builder(toBuilder = true)
@EqualsAndHashCode
@Getter
@NoArgsConstructor
public static class TimePeriod implements Serializable {
private static final long serialVersionUID = 1L;
@PositiveOrZero
private int number;
@NonNull
private TimeUnit timeUnit;
public Instant getSubstractedDate() {
int totalDays = number;
switch (timeUnit) {
case MONTHS: totalDays*=30; break;
case YEARS: totalDays*=365; break;
}
return Instant.now().minus(number, ChronoUnit.DAYS);
}
}
使用java.time.LocalDate
会更好,因为您可以使用LocalDate#minusDays
方法。在我们的案例中,这可能也更有意义。对于Instant
使用DAYS
作为最小粒度并不是很理想。
答案 2 :(得分:1)
我意识到我需要考虑12个月而不是360天,而且 计算leap年。有什么想法吗?
首先,您需要为此确定一个时区。为什么?假设您在(UTC)2019-02-28T23:00:00Z处运行此代码,并且要减去1个月。现在是墨西哥城的2月28日,所以结果应该在1月28日。相比之下,在上海,已经是3月1日,所以结果应该在2月1日。相差3天(72小时)。 / p>
确定了时区后,最简单的方法就是使用ZonedDateTime
。减去后,您始终可以转换为Instant
,这也很简单。
例如:
ZoneId zone = ZoneId.of("Asia/Ashkhabad");
Map<Unit, ChronoUnit> units = Map.of(Unit.days, ChronoUnit.DAYS,
Unit.months, ChronoUnit.MONTHS, Unit.years, ChronoUnit.YEARS);
Time timeToSubtract = new Time(15, Unit.months);
Instant result = ZonedDateTime.now(zone)
.minus(timeToSubtract.getNumber(), units.get(timeToSubtract.getUnit()))
.toInstant();
System.out.println("15 months ago was " + result);
刚运行时(2019-05-08T07:06:45Z)我得到以下输出:
15个月前是2018-02-08T07:06:45.353746Z
我使用的ZonedDateTime.minus
方法可以理解ChronoUnit
,但不能理解您的Unit
枚举,因此,既然您获得了后者,我们就需要翻译(否则您的枚举必须实施TemporalUnit
,但这太过分了)。我正在使用地图进行翻译。我正在以Java 9方式初始化地图。如果您仍然使用Java 8,我相信您可以用其他方式来填充它。
在我的代码中,我假设您的Time
类具有通常的构造函数和吸气剂。
ZonedDateTime
还考虑到一天并非总是24小时。例如,在春季夏季时间(DST)开始并且时钟向前调时,一天只有23个小时。然后在秋天的一天中将时钟调回25小时。
答案 3 :(得分:0)
这就是我最终要做的。谢谢@Yasin Hajaj和@ OleV.V提供正确的答案。但是Olev V.V的答案更准确地解决了这个问题。
将ChronoUnit
添加到Unit
枚举
public enum Unit {
days(ChronoUnit.DAYS),
months(ChronoUnit.MONTHS),
years(ChronoUnit.YEARS);
private final ChronoUnit chronoUnit;
Unit(final ChronoUnit chronoUnit) {
this.chronoUnit = chronoUnit;
}
public ChronoUnit toChronoUnit() {
return chronoUnit;
}
}
还有计算日期的地方,我这样称呼
Time timeToSubtract = new Time(15, Unit.months);
Instant result = ZonedDateTime.now(ZoneId.of("America/New_York"))
.minus(timeToSubtract.getNumber(), units.get(timeToSubtract.getUnit()))
.toInstant();
System.out.println("15 months ago was " + result);
这将返回减去的时间段,其中包括the年和30/31天的月份。