gpt4 book ai didi

java - Java:处理日期

转载 作者:行者123 更新时间:2023-11-30 02:05:08 35 4
gpt4 key购买 nike

我是Java的新手。所以,请忍受我。我有4个变量:

mode =  prior|later|value;(can have either of these 3 values)
occurrence = 2
day = Wednesday
eta = 14:00


我正在尝试实现一种方法,该方法将基于以下条件返回列表 date

情况1: (mode=prior,occurence=2,day=wednesday,eta=14:00)

应该返回从当前月份开始的下个月的前2个星期三的日期。

输出= [2018年8月1日星期三14:00:00、2018年8月8日星期三14:00:00]

情况2:( mode=later,occurence=2,day=wednesday,eta=14:00

应该返回当月下个月的最后2个星期三的日期。

输出= [2018年8月22日星期三14:00:00,2018年8月29日星期三14:00:00]

情况3: (mode=value,occurence=3,day=wednesday,eta=14:00)

应该返回当前月的下个月的第3个星期三的日期。

output = [Wed Aug 15 14:00:00 2018, Wed Aug 29 14:00:00 2018]


这是我到目前为止所做的

public static List<Date> getDates(Calendar c, String mode, int occurrence, int dayNo, String eta) {
List<Date> dates = new ArrayList<Date>();
switch(mode) {
case "value": {
String[] times = eta.split(":");
c.set(Calendar.DAY_OF_WEEK, dayNo);
c.set(Calendar.DAY_OF_WEEK_IN_MONTH, occurrence);
c.set(Calendar.MONTH, Calendar.JULY + 1);
c.set(Calendar.YEAR, 2018);
c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(times[0]));
c.set(Calendar.MINUTE, Integer.parseInt(times[1]));
dates.add(c.getTime());
}
}
return dates;
}


有没有更好的方式来做我所做的事情。还可以有人帮助我实施案例1和2吗?

最佳答案

避免使用旧的日期时间类

您正在使用可怕的旧日期时间类,这些类早在几年前就被java.time类所取代。

特别是,Calendar类(实际上是GregorianCalendar)由ZonedDateTime代替。

使用类型(类)

在可行的情况下,使用智能对象而不是哑字符串。使用适当的类型可使您的代码更具自记录性,确保有效值,提供type-safety,并让编译器捕获您的typos

就您而言,Java已经为大多数数据提供了类型。您可以为“模式”输入自己的类型。

Java中的enum功能比其他语言中常见的功能强大和灵活。有关更多信息,请参见Oracle Tutorial。但是基础很简单,如下所示:

public enum Mode {
PRIOR ,
LATER ,
VALUE
}


对于一周中的某天,请使用 DayOfWeek枚举,预定义七个对象,一周中的每一天一个。例如, DayOfWeek.WEDNESDAY

对于一天中的时间,请使用 LocalTime

LocalTime lt = LocalTime.of( 14 , 0 ) ;


对于当前月份,使用 YearMonth类。

确定当前的年月意味着确定当前的日期。确定当前日期需要一个时区。在任何给定时刻,日期都会在全球范围内变化。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ; // Or "America/Chicago", etc.
YearMonth ym = YearMonth.now( z ) ;


如果有 LocalDate,则可以确定它的年月。

YearMonth ym = YearMonth.from( myLocalDate ) ;


我建议让调用方法确定 YearMonth,而不要使此方法跳过额外的麻烦。 OOP中的一般设计方法是分离或分解责任。我们正在编写的此方法应关注其自身的需求(一个年月值),而不必关心调用方法如何到达其期望的年月,无论是从当前日期还是当前月或上个月开始,等等

最后,如果您的目标是获取时间(带有日期的日期),则还必须指定一个时区。没有时区上下文(或从UTC偏移)的日期+时间没有实际意义。

continent/region的格式指定 proper time zone name,例如 America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如 ESTIST,因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。

因此,将所有这些放在一起,您的方法签名可能如下所示:

public static List< ZonedDateTime > getDates( 
YearMonth ym ,
Mode mode ,
int occurrences ,
DayOfWeek dow ,
LocalTime lt ,
ZoneId z
) { …


逻辑

前两种情况 Mode.PRIORMode.LATER的解决方案是使用 TemporalAdjuster接口。具体来说,在 TemporalAdjusters类中找到的实现可以确定每月的第n个工作日,例如第一个星期三。更具体地说:


firstInMonth​( DayOfWeek dayOfWeek )
lastInMonth​( DayOfWeek dayOfWeek )


这里的主要思想是从该月的第一个(或最后一个)星期几开始。然后逐月逐月向下(向上)工作,每周一次(减去)一次。重复我们的整数 occurrences的限制。

我们可以在 switch枚举上做一个 Mode,如 discussed here。关键点:为清楚起见,我宁愿使用 Mode.PRIOR语法,而不只是使用 PRIOR。但是,Java中晦涩的技术性禁止在 switch中使用该语法。因此, case PRIOR:不是 case Mode.PRIOR:,如示例代码中进一步所示。

我们将所得的 ZonedDateTime对象收集在名为 Listmoments中。

int initialCapacity = 5; // Max five weeks in any month.
List< ZonedDateTime > moments = new ArrayList<>( initialCapacity );


让我们看看三种模式中每种模式的逻辑。

Mode.PRIOR

获取每月的第一天。

    LocalDate firstDowOfMonth = ym.atDay( 1 ).with( TemporalAdjusters.firstInMonth( dow ) );


逐月工作,一次增加一周。

我们可能会超出该月的界限,直到下个月。因此,请检查 YearMonth与启动时是否相同。

    for ( int i = 0 ; i < occurrences ; i++ ) {
LocalDate ld = firstDowOfMonth.plusWeeks( i );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
if ( YearMonth.from( zdt ).equals( ym ) ) { // If in same month…
moments.add( zdt );
}
}


Mode.LATER

这种情况使用与上面相同的逻辑,除了我们从月底开始并逐步进行。获取每月的最后一天,然后一次减去一周。

        // Start with last day-of-week in month.
LocalDate lastDowOfMonth = ym.atDay( 1 ).with( TemporalAdjusters.lastInMonth( dow ) );
// Work our way up through the month, subtracting a week at a time.
for ( int i = 0 ; i < occurrences ; i++ ) {
LocalDate ld = lastDowOfMonth.minusWeeks( i );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
if ( YearMonth.from( zdt ).equals( ym ) ) { // If in same month…
moments.add( zdt );
}
}


因为我们要倒退一段时间,所以我们的 moments集合按时间倒序排列。因此,我们需要排序以按时间顺序显示这些内容。

        Collections.sort( moments ); // If you want the list to be in chronological order, sort.  Otherwise in reverse chronological order for this `Mode.LATER`.


Mode.VALUE

最后一种情况是最简单的:获取每月的第n天。那简直是单线。

        LocalDate nthDowInMonth = ym.atDay( 1 ).with( TemporalAdjusters.dayOfWeekInMonth( occurrences , dow ) );


照常做,做一个 ZonedDateTime

        ZonedDateTime zdt = ZonedDateTime.of( nthDowInMonth , lt , z );


验证月份,因为文档似乎在说超过该月份的限制会将我们带入下个月。在这种情况下,我们的逻辑将省略列表中的日期。因此,我们将 moments作为空列表返回。这意味着调用方法应检查包含元素的列表,因为它可能为空。

        if ( YearMonth.from( zdt ).equals( ym ) ) {  // If in same month…
moments.add( zdt );
}


让我们看看所有的代码。

// Simulate arguments passed.
LocalTime lt = LocalTime.of( 14 , 0 );
ZoneId z = ZoneId.of( "Africa/Tunis" ); // Or "America/Chicago", etc.
YearMonth ym = YearMonth.now( z );
DayOfWeek dow = DayOfWeek.WEDNESDAY;
Mode mode = Mode.PRIOR ; // Mode.PRIOR, Mode.LATER, Mode.VALUE.
int occurrences = 3; // TODO: Add code to verify this value is in range of 1-5, not zero, not >5.

// Logic
int initialCapacity = 5; // Max five weeks in any month.
List< ZonedDateTime > moments = new ArrayList<>( initialCapacity );
switch ( mode ) {
case PRIOR:
// Start with first day-of-week in month.
LocalDate firstDowOfMonth = ym.atDay( 1 ).with( TemporalAdjusters.firstInMonth( dow ) );
// Work our way down through the month, adding a week at a time.
for ( int i = 0 ; i < occurrences ; i++ ) {
LocalDate ld = firstDowOfMonth.plusWeeks( i );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
if ( YearMonth.from( zdt ).equals( ym ) ) { // If in same month…
moments.add( zdt );
}
}
break;

case LATER:
// Start with last day-of-week in month.
LocalDate lastDowOfMonth = ym.atDay( 1 ).with( TemporalAdjusters.lastInMonth( dow ) );
// Work our way up through the month, subtracting a week at a time.
for ( int i = 0 ; i < occurrences ; i++ ) {
LocalDate ld = lastDowOfMonth.minusWeeks( i );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
if ( YearMonth.from( zdt ).equals( ym ) ) { // If in same month…
moments.add( zdt );
}
}
Collections.sort( moments ); // If you want the list to be in chronological order, sort. Otherwise in reverse chronological order for this `Mode.LATER`.
break;

case VALUE:
// Get the nth day-of-week in month.
LocalDate nthDowInMonth = ym.atDay( 1 ).with( TemporalAdjusters.dayOfWeekInMonth( occurrences , dow ) );
ZonedDateTime zdt = ZonedDateTime.of( nthDowInMonth , lt , z );
if ( YearMonth.from( zdt ).equals( ym ) ) { // If in same month…
moments.add( zdt );
}
break;

default: // Defensive programming, testing for unexpected values.
System.out.println( "ERROR - should not be able to reach this point. Unexpected `Mode` enum value." );
break;
}
// return `moments` list from your method.
System.out.println( "moments:\n" + moments );


请注意,我们指定时区中特定日期的指定时间可能无效。例如,在夏令时(DST)的转换过程中。如果是这样, ZonedDateTime类将根据需要进行调整。请务必阅读文档,以确保您了解并同意其调整算法。



关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧 legacy日期时间类,例如 java.util.DateCalendarSimpleDateFormat

现在位于 Joda-Time中的 maintenance mode项目建议迁移到 java.time类。

要了解更多信息,请参见 Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为 JSR 310

您可以直接与数据库交换java.time对象。使用与 JDBC driver或更高版本兼容的 JDBC 4.2。不需要字符串,不需要 java.sql.*类。

在哪里获取java.time类?


Java SE 8Java SE 9Java SE 10和更高版本


内置的
标准Java API的一部分,具有捆绑的实现。
Java 9添加了一些次要功能和修复。

Java SE 6Java SE 7


ThreeTen-Backport中的许多java.time功能都已反向移植到Java 6和7。

Android


更高版本的Android捆绑了java.time类的实现。
对于较早的Android(<26), ThreeTenABP项目改编为 ThreeTen-Backport(如上所述)。请参见 How to use ThreeTenABP…



ThreeTen-Extra项目使用其他类扩展了java.time。该项目是将来可能向java.time添加内容的试验场。您可能会在这里找到一些有用的类,例如 IntervalYearWeekYearQuartermore

关于java - Java:处理日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51600118/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com