我正在研究一些会计逻辑.逻辑是,在一个季度的第一个月发生的会计必须具有上一季度末的价值日期.我知道我可以将月份表示为一个时期.但我不知道如何代表四分之一年的经常性时期.
我能够使用joda-time类进行计算,这将给出上一季度末的价值日期.但是,我想将"每个季度的第一个月"表示为我在计算中使用的单个值.
那么在joda-time中是否有一些API非常适合代表这种反复出现的时期?
一些示例日期是:
date of invoce | value date
2013-01-01 | 2012-12-31
2013-01-31 | 2012-12-31
2013-02-01 | 2013-02-01
2013-03-31 | 2013-03-31
2013-04-01 | 2013-03-31
Run Code Online (Sandbox Code Playgroud)
好的,这里是评论中要求的更具说明性的例子:会计逻辑是关于你必须申请的一种养老基金.您在接下来的一年,即2013年1月1日申请2012年的退休金.它将在2013年4月15日授予您.自4月是本季度的第一个月,授予将具有其价值日期定于3月31日.所有在一个季度内计入的养老金都在该季度结束后的1个月和5天内支付.因此,即使您在4月份获得了养老金,您仍然可以在5月5日获得养老金.否则你将不得不等到9月5日之前付款.
但我真的不知道这个例子应该如何帮助.这个问题实际上是关于使用joda-time类建模"每个季度的每个第一个月",甚至是实现一些joda-time的API.
我也必须实现这一点.这是一个乍一看似乎没问题的实现.
public class QuarterPeriods {
public static LocalDate quarterStartFor(LocalDate date) {
return date.withDayOfMonth(1).withMonthOfYear((((date.getMonthOfYear() - 1) / 3) * 3) + 1);
}
public static LocalDate quarterEndFor(LocalDate date) {
return quarterStartFor(date).plusMonths(3).minusDays(1);
}
}
public class QuarterPeriodsTest {
@Test
public void startOfQuarter() throws Exception {
assertThat(quarterStartFor(StubDates.dateOf("2011/02/02")), equalTo(StubDates.dateOf("2011/01/01")));
assertThat(quarterStartFor(StubDates.dateOf("2011/01/01")), equalTo(StubDates.dateOf("2011/01/01")));
assertThat(quarterStartFor(StubDates.dateOf("2011/02/02")), equalTo(StubDates.dateOf("2011/01/01")));
assertThat(quarterStartFor(StubDates.dateOf("2011/04/01")), equalTo(StubDates.dateOf("2011/04/01")));
assertThat(quarterStartFor(StubDates.dateOf("2011/07/01")), equalTo(StubDates.dateOf("2011/07/01")));
assertThat(quarterStartFor(StubDates.dateOf("2011/12/19")), equalTo(StubDates.dateOf("2011/10/01")));
}
@Test
public void endOfQuarter() throws Exception {
assertThat(quarterEndFor(StubDates.dateOf("2011/02/02")), equalTo(StubDates.dateOf("2011/03/31")));
assertThat(quarterEndFor(StubDates.dateOf("2011/01/01")), equalTo(StubDates.dateOf("2011/03/31")));
assertThat(quarterEndFor(StubDates.dateOf("2011/02/02")), equalTo(StubDates.dateOf("2011/03/31")));
assertThat(quarterEndFor(StubDates.dateOf("2011/04/01")), equalTo(StubDates.dateOf("2011/06/30")));
assertThat(quarterEndFor(StubDates.dateOf("2011/07/01")), equalTo(StubDates.dateOf("2011/09/30")));
assertThat(quarterEndFor(StubDates.dateOf("2011/12/19")), equalTo(StubDates.dateOf("2011/12/31")));
}
}
public class StubDates {
public static LocalDate dateOf(String date) {
return DateTimeFormat.forPattern("yyyy/MM/dd").withZone(DateTimeZone.UTC).parseDateTime(date).toLocalDate();
}
}
Run Code Online (Sandbox Code Playgroud)
您需要编写一个例程,在该例程中传递日期并返回表示上一季度最后一天的日期.实际上,这听起来像是方法的好名字,以及对问题的更好总结:endingDateOfPreviousQuarter( someDate ).
或者在我自己的命名约定中命名,我用start它stop来表示包容性而不是排他性边界stopDateOfPreviousQuarter( someDate ).
我会用一对方法做到这一点.
startDateOfQuarter( someDate )
stopDateOfPreviousQuarter( someDate )
Voilà,您有上一季度最后一天的日期.
这里的主要思想是,通常最好找到一个时间元素的开头,然后使用minus,而不是试图直接获得结束点.获取一小时,一天,一周,一个月或一个季度的开头.这避免了闰日,闰秒†,夏令时(DST),记忆哪个月有30对31天的错误,以及分数秒的问题,分辨率不同使得很难确定一小时的最后时刻或天.此外,至少在我的经验中,关注时期的开始可以清晰地思考日期时间.
ISO 8601不承认宿舍.有些人扩展规范,使用"Q"结合一些标识符,如本维基中所述.
Joda-Time 2不支持季度,正如2011年的讨论所述.
ISO 8601精确定义了52或53个编号周的定义.Joda-Time支持这个概念,由weekOfWeekYear代表.一些企业通过1到52/53范围的子集来定义他们的季度.
或者您可以在一年的第3个月,第6个月,第9个月和第12个月结束时定义您的宿舍.Joda-Time具有DateTime类的构造函数,可用于指定月份编号.注意使用withTimeAtStartOfDay()方法让Joda-Time完成当天第一时刻的工作,因为并非所有时区的所有日子都有午夜.
org.joda.time.DateTimeZone parisDateTimeZone = org.joda.time.DateTimeZone.forID( "Europe/Paris" );
org.joda.time.DateTime q1Start = new org.joda.time.DateTime(2013, 1, 1, 0, 0, parisDateTimeZone ).withTimeAtStartOfDay();
org.joda.time.DateTime q2Start = new org.joda.time.DateTime(2013, 4, 1, 0, 0, parisDateTimeZone ).withTimeAtStartOfDay();
System.out.println( "Q1 begins in Paris FR: " + q1Start );
System.out.println( "Q2 begins in Paris FR: " + q2Start );
// When querying a database or comparing items in a collection to find Q1 data,
// Look for: (GreaterThanOrEqualTo q1Start) AND (LessThan q2Start)
Run Code Online (Sandbox Code Playgroud)
如果您绝对只想要日期而没有任何时间元素,请使用Joda-Time的LocalDate类.该类与DateTime类一样运行minusDays()方法.
顺便说一下,考虑一下你是处理简单日期(没有时间)还是日期时间.例如,您可能会认为发票仅使用简单的日期,但实际上它们通常在收到时使用时钟机器盖章,其中包括可能因法律和审计原因需要记录的时间.此外,通常数据库将日期值存储为基于UTC的日期时间(没有时区偏移).
†Joda-Time忽略了闰秒,但我的观点仍然存在.
| 归档时间: |
|
| 查看次数: |
3882 次 |
| 最近记录: |