java - 预约类

标签 java date object

我正在尝试创建一种将约会添加到arraylist约会日历的方法。此方法将验证日期,以查看用户输入是否与我的代码中的SimpleDateFormat相等,约会的startTime和endTime以及是否将来出现。

我尝试使用java Date api进行检查,但是当我尝试扩展类以获取对属性的访问权限时,总是会在编译时出错。所以总的来说,我的问题是将约会类型的对象与日期类型的对象进行比较的最佳方法是什么?我尝试使用accesors来getDate()以及startTime和endTime,但是它不允许我也使用它们。

public AppointmentDate(String appString)
{
    // 1) split ithe string into Date/from/to
    // 2) consturct the Date object for the appDate
    // 3) consturct the Date object for the startTime
    // 4) consturct the Date object for the endTime

    String[] appDetails = appString.split(",");

    if(appDetails.length == 2)
    {
        try {
            SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
            this.appDate = df.parse(appDetails[0]);
            DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy,mm:HH");
            String dFormat = appDetails[0] + "," + appDetails[1];
            this.startTime = formatter.parse(dFormat);
            dFormat = appDetails[0] + "," + appDetails[2];
            this.endTime = formatter.parse(dFormat);
        }
        catch (Exception ex)
        {

        }
    }

    else 
    {
        System.out.print("User Date is Invalid");
    }
}
public void setStartTime(Date startTime) 
{
    this.startTime = startTime;
}

public Date getStartTime()
{
    return startTime;
}

public void setEndTime(Date endTime) 
{
    this.endTime = endTime;
}

public Date getEndTime()
{
    return endTime;
}

public void setAppdate(Date appDate) 
{
    this.appDate = appDate;
}

public Date getAppDate()
{
    return appDate;
}


public void add(Appointment a) 
{
    if (a.equals(a.getDate()))
    {
        if(a.getStartTime() < a.getEndTime())
        {

        }
    }
    else
    {
        System.out.print("");
    }

}

最佳答案

静态块(几乎)

您用于上课的代码在错误的位置。您将其停留在类的顶部,这在语法上是不正确的。我们可以在顶部以static block的形式运行代码,但需要将其标记为static { … }。根据我的经验,静态块并不常用。当然,这不是您在那做的正确地方。

main方法

相反,您应该使用a main method。这个非OOP的小东西是一个技巧,是一种技巧,可以解决chicken-or-the-egg的难题,使我们从无应用程序运行到我们的OOP天堂概念,其中有一堆对象漂浮着并将消息传递给另一个。

初学Java时,请勿尝试理解main方法的所有语法和用途。只是将其视为使应用程序运行所必需的邪恶,它仅仅是执行应用程序的入口。重点学习OOP概念和实践。稍后,main方法和语法会更有意义。

存取器

这是示例代码的简化重写。为了简单起见,我们仅使用LocalDate,足以显示(a)main方法和(b)getter / setter accessor methods

package com.basilbourque.example;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

public class AppointmentDate {
    private LocalDate localDate;

    // Constructor
    public AppointmentDate ( LocalDate localDate ) {
        this.localDate = localDate;
    }

    public LocalDate getLocalDate ( ) {
        return localDate;
    }

    public void setLocalDate ( LocalDate localDate ) {
        this.localDate = localDate;
    }

    @Override
    public String toString ( ) {
        return "AppointmentDate{ " +
                "localDate=" + localDate +
                " }";
    }

    // Not really a part of this class. A `main` method is just a hack to get our app launched.
    public static void main ( String[] args ) {
        String input = "23/01/2018";
        DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
        LocalDate ld = LocalDate.parse( input , f );
        AppointmentDate ad = new AppointmentDate( ld );
        ad.setLocalDate( ld.plusWeeks( 1 ) );
        LocalDate newValue = ad.getLocalDate();
        System.out.println( newValue.toString() );  // Generate text representing the value of this `LocalDate` object in standard ISO 8601 format.

        List < AppointmentDate > list = new ArrayList <>( 3 );
        list.add( ad );
        list.add( new AppointmentDate( LocalDate.parse( "2018-02-13" ) ) );
        list.add( new AppointmentDate( LocalDate.parse( "2018-12-21" ) ) );
        System.out.println( list );
    }
}



  2018-01-30
  
  [AppointmentDate {localDate = 2018-01-30},AppointmentDate {localDate = 2018-02-13},AppointmentDate {localDate = 2018-12-21}]


java.time

您使用的是可怕的旧日期时间类,而该类早已被java.time类取代。切勿使用DateCalendarSimpleDateFormat等。

预约很棘手

尽管约会跟踪从直观上看似乎很简单,但实际上您正在研究一个非常棘手的主题。

核心问题是,全世界的政客都喜欢重新定义其管辖范围内的时区。他们经常这样做。他们在相对安静和动荡时期都这样做。

近几十年来,美国和加拿大已多次改变补偿标准。在过去的几年中,土耳其和俄罗斯已经改变了多次使用DST的想法。

政治家很少提前通知就更改时区。尽管这在越来越多的计算机化社会中引起了越来越大的骚动,但通知似乎越来越短。就在上个月,Morocco announced他们的国家将永久保留夏令时(DST),在周五取消了该周日计划的DST转换,留下0个工作日警告-这对IT员工来说真是一团糟。今年5月,North Korea slipped their clock与韩国同步进行了半小时,显然立即生效(根本没有提前通知)。

这些频繁且不可预测的变化意味着我们不能负责任地将未来的约会作为时刻作为时间轴上的特定点进行跟踪。当我们说诸如“ 1月23日下午3点”之类的话时,通常是指政客可能对时钟进行更改后的下午3点。

因此,我们必须将将来的约会存储为日期和时间,而没有时区或UTC偏移。然后,在计算日历时,我们必须针对当天当前定义的预期时区动态应用规则。如果我们今天进行一次动态确定,然后再三天进行一次动态确定,如果政客宣布了时区定义的更改,并且我们能够在操作系统中更新tzdata数据文件,数据库引擎,Java虚拟机和各种库,那么我们将在另一个时刻到达。

LocalDateTime

Java中的Local…类型故意缺少任何时区或从UTC偏移的概念。所以他们不能代表一个时刻。因此,我们从不使用这些信息来确定过去发生的实际事件。但是这些类型是我们未来约会所需要的。

LocalDateTime类表示具有一天中时间的日期,没有任何区域/偏移量。

LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 15 , 0 ) ;  // 3 PM in 24-hour time.
LocalDateTime ldt= LocalDateTime.of( ld , lt ) ;


ZonedDateTime

在计算日历时,当我们需要特定的时刻时,我们应用时区(ZoneId)来获取ZonedDateTime对象。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;  // Determine a moment, a specific point on the timeline.


Instant

我们可以通过提取Instant在UTC中查看同一时刻。

Instant instant = zdt.toInstant() ;   // Adjust to UTC.


Duration

通常最好将约会存储为起点和持续时间。无需存储停止点,因为可以计算得出。

Duration d = Duration.ofHours( 1 ) ;  // A one-hour appointment.


尽管我们通常希望调整到一个时区以向用户显示,但通常是在幕后进行,最佳做法是跟踪UTC中的时刻。因此,按矩计算的约会的起点和终点应作为一对Instant对象来完成。

Instant start = ldt.atZone( z ).toInstant() ;
Instant stop = start.plus( d ) ;


Interval

我们可以利用一个类来表示这对Instant对象Interval

该类可在ThreeTen-Extra库中找到,该库由与Joda-Time,JSR 310和java.time项目Stephen Colebourne领导相同的人领导。

此类具有非常方便的比较方法,例如abutsoverlapscontains等。您可能希望在调度应用程序中使用这些方法。

Appointment.java

放在一起,我们得到一个像这样的类:

package com.basilbourque.example;

import org.threeten.extra.Interval;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Appointment {
    private LocalDateTime start;
    private Duration duration;

    // Constructor.
    public Appointment ( LocalDateTime start , Duration duration ) {
        this.start = start;
        this.duration = duration;
    }

    // Might add some getter/setter methods in here.

    // Dynamically determine the start and stop points of this appointment, given today’s definition of the intended time zone.
    public Interval toInterval ( ZoneId zoneId ) {
        ZonedDateTime zdtStart = this.start.atZone( zoneId );
        Interval interval = Interval.of( zdtStart.toInstant() , this.duration );
        return interval;
    }

}


当通过调用Interval方法生成toInterval时,可能需要单独的开始时刻和停止时刻。

Instant start = interval.getStart() ;
Instant stop = interval.getEnd() ;


根据定义,这两个Instant对象位于UTC中。如果要通过特定地区的人们所使用的挂钟时间的镜头来查看它们,请应用ZoneId以获取ZonedDateTime对象。

ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdtStart = start.atZone( z ) ;  // Adjust from UTC to some time zone. Same moment, same point on the timeline, different wall-clock time.
ZonedDateTime zdtStop = stop.atZone( z ) ;


未来

您询问是否要检查此约会是否将来。同样,我们需要一个时区来正确回答。目前,世界各地的时区范围大约为26到27小时。因此,在当前时刻的许多小时内,如果不考虑时区,我们就无法确定LocalDateTime是将来还是过去。

因此,让我们为将来需要增加时区的方法进行测试。

// Dynamically determine if this appointment will be in the future for some specific time zone.
public Boolean isFuture ( ZoneId zoneId ) {
    Objects.requireNonNull( zoneId , "Must pass a time zone to determine if an appointment is in the future. Message # e1c64bc1-9a44-4d15-b20d-e68414fb5ab5.");
    ZonedDateTime zdtStart = this.start.atZone( zoneId );
    ZonedDateTime zdtNow = ZonedDateTime.now( zoneId );
    boolean isInTheFuture = zdtNow.isBefore( zdtStart );
    return isInTheFuture ;
}


开始/停止时刻

在动态确定力矩时继续使用相同的主题,让我们添加一些方法来返回开始力矩(包括端点)和停止力矩(包括端点)。如上所述,这需要经过一个时区。

调用程序员可以自己完成这项工作。但是我怀疑可能经常需要这样做,以保证方便地添加这些方法。

// Get start moment for a particular time zone.
public ZonedDateTime toStartMoment ( ZoneId zoneId ) {
    ZonedDateTime zdt = this.toInterval( zoneId ).getStart().atZone( zoneId );
    return zdt;
}

// Get stop moment for a particular time zone.
public ZonedDateTime toStopMoment ( ZoneId zoneId ) {
    ZonedDateTime zdt = this.toInterval( zoneId ).getEnd().atZone( zoneId );
    return zdt;
}


注意,我没有用get…命名这些方法。访问器方法,获取器和设置器,按照惯例,意味着访问存储在对象中的简单属性。但是这里我们不存储ZonedDateTime对象。这些是动态确定的,因此使用get…方法可能会产生误导。相反,我尝试遵循naming conventions laid down in the java.time project

不变的对象

从java.time项目中学习的另一课是immutable objects模式。

某些种类的类适合只读,创建但不能修改。 java.time类肯定合格。例如,预计发票会“变异”(更改),作为程序员,直觉上我不希望发票上的日期发生更改,除非我用新对象明确替换了日期。因此,我希望发票成为可变对象,但我希望存储在该发票上的LocalDate对象是不可变的。

我怀疑我们的Appointment类也可能最好设计为不可变的。因此,我们不涉及任何setter方法。若要有效地更改计划应用程序中的约会,请基于现有Appointment对象的某些值创建一个新的Appointment对象。在java.time类中,请注意如何使用各种with方法来完成此操作,其中这些方法会根据原始值(但进行一些更改)返回一个新对象。

Appointment.java版本2

让我们将所有这些放到一个示例类中。

让我们添加一个main方法来练习此类。首先,我们创建一个约会,并查看其在UTC中动态确定的时刻。其次,我们在集合中收集一些Appointment对象。

我们添加了toString方法替代来报告对象的状态。

package com.basilbourque.example;

import org.threeten.extra.Interval;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

// An example class to show date-time handling for future appointments.
// Not necessarily ready for production use. Use at your own risk.
// Methods named according to the java.time naming conventions:
// https://docs.oracle.com/javase/tutorial/datetime/overview/naming.html
public class Appointment {
    private LocalDateTime start;
    private Duration duration;

    // Constructor.
    public Appointment ( LocalDateTime start , Duration duration ) {
        this.start = start;
        this.duration = duration;
    }

    // Dynamically determine the start and stop points of this appointment, given today’s definition of the intended time zone.
    public Interval toInterval ( ZoneId zoneId ) {
        Objects.requireNonNull( zoneId , "Must pass a time zone to get the start/stop interval of an appointment. Message # bbf021e6-baa7-468d-83ad-cf73acb6702e." );
        ZonedDateTime zdtStart = this.start.atZone( zoneId );
        Interval interval = Interval.of( zdtStart.toInstant() , this.duration );
        return interval;
    }

    // Get start moment for a particular time zone.
    public ZonedDateTime toStartMoment ( ZoneId zoneId ) {
        ZonedDateTime zdt = this.toInterval( zoneId ).getStart().atZone( zoneId );
        return zdt;
    }

    // Get stop moment for a particular time zone.
    public ZonedDateTime toStopMoment ( ZoneId zoneId ) {
        ZonedDateTime zdt = this.toInterval( zoneId ).getEnd().atZone( zoneId );
        return zdt;
    }

    // Dynamically determine if this appointment will be in the future for some specific time zone.
    public Boolean isFuture ( ZoneId zoneId ) {
        Objects.requireNonNull( zoneId , "Must pass a time zone to determine if an appointment is in the future. Message # e1c64bc1-9a44-4d15-b20d-e68414fb5ab5." );
        ZonedDateTime zdtStart = this.start.atZone( zoneId );
        ZonedDateTime zdtNow = ZonedDateTime.now( zoneId );
        boolean isInTheFuture = zdtNow.isBefore( zdtStart );
        return isInTheFuture;
    }

    // -----------|  Object overrides  |---------------------------
    @Override
    public String toString ( ) {
        return "Appointment{ " +
                "start=" + start +
                " | duration=" + duration +
                " }";
    }

    // -----------|  main  |-------------
    public static void main ( String[] args ) {
        // See if a new appointment is in the future.
        Appointment a = new Appointment( LocalDateTime.of( 2018 , 12 , 25 , 0 , 0 , 0 , 0 ) , Duration.ofHours( 2 ) );  
        ZoneId z = ZoneId.of( "America/Montreal" );
        System.out.println( "For time zone: " + z + ", appointment interval is: " + a.toInterval( z ) );
        System.out.println( "Start: " + a.toStartMoment( z ) );
        System.out.println( "Stop: " + a.toStopMoment( z ) );

        Boolean isFuture = a.isFuture( z );
        System.out.println( a.toString() + " is future t/f: " + isFuture );

        // Collect some appointments.
        List < Appointment > list = new ArrayList <>( 3 );
        list.add( a );
        list.add( new Appointment( LocalDateTime.of( 2018 , 12 , 13 , 15 , 0 , 0 , 0 ) , Duration.ofMinutes( 90 ) ) );
        list.add( new Appointment( LocalDateTime.of( 2018 , 12 , 30 , 16 , 0 , 0 , 0 ) , Duration.ofHours( 1 ) ) );
        System.out.println( list );
    }

}


运行时。


  时区:美国/蒙特利尔,约会间隔为:2018-12-25T05:00:00Z / 2018-12-25T07:00:00Z
  
  开始时间:2018-12-25T00:00-05:00 [美国/蒙特利尔]
  
  停止:2018-12-25T02:00-05:00 [美国/蒙特利尔]
  
  预约{start = 2018-12-25T00:00 | duration = PT2H}是将来的t / f:true
  
  [预约{start = 2018-12-25T00:00 | duration = PT2H},预约{start = 2018-12-13T15:00 | duration = PT1H30M},预约{start = 2018-12-30T16:00 |持续时间= PT1H}]




关于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 10Java SE 11和更高版本-具有捆绑实现的标准Java API的一部分。


Java 9添加了一些次要功能和修复。

Java SE 6Java SE 7


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

Android


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



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

关于java - 预约类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53403042/

相关文章:

object - 如果 vue.js 2 上的对象为空,如何添加条件?

javascript - 视野中的黄色物体 - 三个 JS

java - 通过jni将jint数组从c返回到java

java - JSF 页面更改后未部署

php - 在 php 中为任意日期添加设定时间

java - 如何在Java中获取不完整一周的第一天/最后一天

javascript - 如何使用 NestJs @Body 解析 JSON 请求中的日期

javascript - 将对象数组转换为具有数组值的对象

java - 如何在 Spring MVC 中使用转发处理 Controller 之间的 ModelMap 的有效方法

java - Tomcat9 有问题