使用 GregorianCalendar 操作和比较日期,无法使代码正常工作

Manipulating and comparing dates with GregorianCalendar and can't get the code to work properly

我正在努力寻找我的代码中的错误。 paytotal 在应该有数字的时候出现了 0。

firstDayOfPaycheck 是 2020 年 10 月 23 日。

lastDayOfPaycheck 是 2020 年 11 月 6 日。

我的简单日期格式 sdf 是“MMM dd, yyyy”。

string dateInQuestion 传入 runPayroll 的是“2020 年 10 月 31 日”,它最初来自与上述相同的 sdf。

我是 java 的新手,还没有处理过像这样操作日历的问题。感觉下面的代码应该可以工作。

 private void runPayroll(String dateInQuestion, long payForTask){   
     c.setTime(firstDayOfPaycheck);
        
        //loop through days of paycheck. number from time.compareTo(time2) is negative while time is before time2 
        while(c.getTime().compareTo(lastDayOfPaycheck)<=0){

            if(dateInQuestion != null) {

                Date questionDate = sdf.parse(dateInQuestion, new ParsePosition(0));
                if (c.getTime().compareTo(questionDate) == 0) {
                    payTotal += payForTask;
                }
            }
            c.add(Calendar.DAY_OF_YEAR, 1);
        }
} //ran inside the query to get the total pay

private void buildPayrollDash(){
    String strPayrollAmt = "$" + payTotal;


    String startDate = sdf.format(firstDayOfPaycheck);
    String trimmedStart = startDate.split(",")[0]; //cuts out the year in the date
    String endDate = sdf.format(lastDayOfPaycheck);
    String trimmedEnd = endDate.split(",")[0];
    int holdBack = sharedPreferences.getInt("payroll holdback", 7);
    c.setTime(lastDayOfPaycheck);
    c.add(Calendar.DAY_OF_YEAR, holdBack);
    String payDate = sdf.format(c.getTime());
    String trimmedPaydate = payDate.split(",")[0];

    tvPayrollTimefame.setText("Pay from " + trimmedStart + " - " + trimmedEnd);
    tvPayrollAmount.setText(strPayrollAmt + " due " + trimmedPaydate);

I'm struggling to find the error in my code here.

您使用的日期时间 类 多年前已被现代 java.time 类 取代。切勿使用 DateCalendarGregorianCalendar 或他们的亲属。

firstDayOfPaycheck is the date Oct. 23rd 2020.

使用 LocalDate 表示没有时间和时区的日期。

LocalDate firstDayOfPayPeriod = LocalDate.of( 2020 , Month.OCTOBER , 23 ) ;

lastDayOfPaycheck is the date Nov. 6 2020.

如果使用半开方法定义时间跨度,您会发现日期时间处理会容易得多。开头包含,结尾不包含。因此,与其关注支付期的最后一天,不如关注下一个支付期的第一天。

LocalDate firstDayOfSuccessivePayPeriod = LocalDate.of( 2020 , 11 , 7 ) ;

提示:您可以将支付期的日期范围表示为您的 Java 项目的 LocalDateRange object if you add the ThreeTen-Extra 库。

My Simple date format sdf is "MMM dd, yyyy".

您不应将业务逻辑与本地化代码混合在一起。日期时间的自定义格式只能用于向用户展示。

当以文本形式将日期时间值作为数据交换时,请使用标准 ISO 8601 格式。对于仅限日期的值,标准格式为 YYYY-MM-DD。 java.time 默认使用 ISO 8601 格式,因此无需指定任何格式模式。

string dateInQuestion passed into runPayroll is "Oct. 31, 2020" which came originally from the same sdf as above.

LocalDate dateInQuestion = LocalDate.parse( "2020-10-31" ) ;

如果您必须适应格式化日期字符串而不是标准 ISO 8601 格式的输入,请使用 DateTimeFormatter。这已在 Stack Overflow 上多次提及,因此请搜索更多信息。

与其稍后检查有效数据,不如在代码中尽早检查您的输入。俗话说“快速失败”。

try
{
    LocalDate dateInQuestion = LocalDate.parse( "2020-10-31" );
}
catch ( DateTimeParseException e )
{
    // … Handle faulty input.
    e.printStackTrace();
}

I'm new to java and haven't dealt with manipulating the calendar like this. It feels like the code below should work.

使用 java.time 时,您的代码会简单得多。一方面,java.time 类 提供方便的 isBeforeisAfterisEqual 方法,因此不需要对于笨拙的 compareTo 调用。

LocalDate firstDayOfPayPeriod = LocalDate.of( 2020 , Month.OCTOBER , 23 );
LocalDate firstDayOfSuccessivePayPeriod = LocalDate.of( 2020 , 11 , 7 );

String input = "2020-10-31";
LocalDate dateInQuestion = null;
try
{
    dateInQuestion = LocalDate.parse( input );
}
catch ( DateTimeParseException e )
{
    // Handle faulty input.
    e.printStackTrace();
}

// Validate dates.
Objects.requireNonNull( firstDayOfPayPeriod );
Objects.requireNonNull( firstDayOfSuccessivePayPeriod );
Objects.requireNonNull( dateInQuestion );
if ( ! firstDayOfPayPeriod.isBefore( firstDayOfSuccessivePayPeriod ) )
{
    throw new IllegalStateException( "…" );
}
if ( dateInQuestion.isBefore( firstDayOfPayPeriod ) )
{
    throw new IllegalStateException( "…" );
}
if ( ! dateInQuestion.isBefore( firstDayOfSuccessivePayPeriod ) )
{
    throw new IllegalStateException( "…" );
}


long payPerDay = 100;
long partialPay = 0;

LocalDate localDate = firstDayOfPayPeriod;
while ( localDate.isBefore( firstDayOfSuccessivePayPeriod ) )
{
    if ( localDate.isBefore( dateInQuestion ) )
    {
        partialPay = ( partialPay + payPerDay );
    }

    // Set up the next loop.
    // Notice that java.time uses immutable objects. So we generate a new object based on another’s values rather than alter (mutate) the original.
    localDate = localDate.plusDays( 1 ); // Increment to next date.
}

System.out.println( "Partial pay earned from firstDayOfPayPeriod " + firstDayOfPayPeriod + " to dateInQuestion " + dateInQuestion + " is " + partialPay );

看到这个 code run live on IdeOne.com

Partial pay earned from firstDayOfPayPeriod 2020-10-23 to dateInQuestion 2020-10-31 is 800

有了更多的编程经验 Java,您可能希望使用流来完成此类工作。参见 LocalDate::datesUntil

顺便说一句,如果您想跳过周末,请添加如下内容:

Set< DayOfWeek > weekend = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY ) ;
…
if ( weekend.contains( localDate.getDayOfWeek() ) ) { … }

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

Joda-Time project, now in maintenance mode, advises migration to the java.time 类.

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 类。 Hibernate 5 和 JPA 2.2 支持 java.time.

在哪里获取 java.time 类?