代码之家  ›  专栏  ›  技术社区  ›  MrEmper

Java-自动生成当前日期+用户输入时间

  •  1
  • MrEmper  · 技术社区  · 6 年前

    目前,我得到了一个带有日期数据类型的“航班”类;出发和到达日期时间。

    通过用户输入添加航班。日期应自动为当前日期,时间由用户选择。这意味着一个人只需输入HH:mm。

    目前,所有的选择都有点混乱;时间戳、日期、本地时间等。

    如何使用扫描仪对此问题进行简单的用户输入? 它应该是今天的日期,添加包含时间的用户输入,并将其添加到一起以适应我的日期数据类型。

    有人知道如何做到这一点,或者可以提供一些提示/最佳做法吗?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Dimitar Spasovski    6 年前

    既然您说您正在开发一个桌面应用程序,并且需要当前日期(在pc上),那么您可以使用以下组合 LocalDate LocalTime 实现你的目标。

    代码如下:

    public static void main(String[] args) {
    LocalDate currentDate = LocalDate.now();
    LocalTime userInputTime = null;
    
    Scanner sc = new Scanner(System.in);
    String dateTimeLine = sc.nextLine();
    sc.close();
    
    DateTimeFormatter dt = DateTimeFormatter.ofPattern("HH:mm");
    userInputTime = LocalTime.parse(dateTimeLine,dtf);
    
    System.err.println(LocalDateTime.of(currentDate, userInputTime));
    }
    

    首先,您使用 LocalDate.now() 以生成当前日期(仅日期,不含小时、分钟和秒)。

    接下来我们使用 Scanner 以读取用户输入的字符串。 为了将字符串转换为 当地时间 (这个类只包含关于一天中时间的信息,所以它有小时、分钟、秒和纳秒的值),我们必须定义 DateTimeFormatter 这个 日期时间格式 定义如何将字符串转换为 当地时间 例子

    在我刚刚编写的代码中,我说过字符串输入的类型是“小时:分钟”。例如,可能的值包括:

    “10:25”-10小时25分钟,

    “23:00”-23小时零分,

    “02:13”-2小时13分钟。

    在我们创建 当地时间 对象,我们所要做的就是连接date和time对象,以便创建LocalDateTime对象,这是在以下行中完成的:

    LocalDateTime.of(currentDate, userInputTime)
    

    因此,假设您当前电脑上的日期是2018年5月6日。如果运行程序并在控制台中输入10:50,则输出应为 LocalDateTime 以2018-05-06为日期,以10小时50分钟为时间的对象。

    需要注意的是,这一行:

    userInputTime = LocalTime.parse(dateTimeLine,dtf);

    将抛出 java.time.format.DateTimeParseException 如果用户输入的字符串不符合要求的格式。

        2
  •  1
  •   Basil Bourque    6 年前

    tl;博士

    LocalDateTime.of(                 // A `LocalDateTime` represents a set of *potential* moments along a range of about 26-27 hours. Not an actual moment, not a point on the timeline.
        LocalDate.systemDefault() ,   // Get the JVM’s current default time zone. Can change at any moment *during* runtime. When crucial, always confirm with the user.
        LocalTime.parse( "14:57" )    // Parse a string in standard ISO 8601 format as a time-of-day without regard for time zone or offset-from-UTC.
    )                                 // Returns a `LocalDateTime` object.
    .atZone(                          // Determine an actual moment, a point on the timeline.
        ZoneId( "Africa/Tunis" )      // Specify a time zone as `Continent/Region`, never as 3-4 letter pseudo-zones such as `PST`, `CST`, or `IST`.
    )                                 // Returns a `ZonedDateTime` object.
    .toInstant()                      // Extracts a `Instant` object from the `ZonedDateTime` object, always in UTC by default.
    

    详细信息

    目前有点混乱

    日期时间处理为 非常 令人困惑的工作。

    提示:

    • 忘记你自己的时区吧。从以下方面考虑 UTC 而不是你自己的狭隘时区。
    • 了解真实时刻(时间轴上的点)和日期时间近似值之间的差异 在时间轴上,通常称为“本地”值。
    • 阅读堆栈溢出或internet上其他位置有关日期时间的信息时要小心。你会遇到糟糕的建议和许多错误的解决方案。

    拥有所有的选择;时间戳、日期、本地时间等。

    永远不要使用与Java最早版本捆绑在一起的麻烦的旧遗留日期时间类。从不使用 java.sql.Timestamp ,则, java.util.Date ,则, java.util.Calendar 等等

    仅使用中的类 java.time package

    这个 JAVA时间 课程是业界领先的日期-时间框架。经过精心设计和深思熟虑,从 Joda-Time 项目成功。

    有人知道如何做到这一点,或者可以提供一些提示/最佳做法吗?

    你可能会后悔你的要求。继续读下去。

    目前,我得到了一个带有日期数据类型的“航班”类;出发和到达日期时间。

    因此,请定义 Flight

    在现实生活中,飞行在未来发生的距离足够远,以至于我们冒着政客改变时区定义的风险。最常见的变化是采用/删除/更改 Daylight Saving Time (DST) .但由于各种原因,会定期进行任意更改。我们可以对这种变化的明智性/理智性进行辩论,但事实是它们确实发生了。这种情况经常发生,因为政客们似乎奇怪地倾向于在世界各地的许多国家做出这些改变。几乎所有人都是在几乎没有预警的情况下这样做的,有时只是几周。甚至没有任何警告 North Korea did this week

    我有 了解航空公司实际上是如何工作的,但通过浏览航空公司的时间表和各种读数,他们似乎试图利用出发地点的分区时间来维持他们的时间表。因此,如果航班计划在上午6点起飞,他们会在DST转换的前一天、第二天和第二天保留该航班时间表。如果这确实是一般意图,那就意味着在一个DST切换上无所事事地消磨时间,同时在另一个DST切换上努力节省一个小时。显然地 Amtrak adopts this practice 为了它的火车。让我们继续这个方法。

    使用这种假想的时间表方法意味着我们无法确定未来早上6点的确切时间。因此,我们需要记录我们对那个日期和一天中的那个时间的渴望,而不应用时区。但我们必须记录下所需的时区,以便我们知道在什么情况下,我们可以稍后确定确切的时刻,何时足够接近,我们不必担心时区的变化。

    所以我们使用 LocalDate LocalTime 类型,因为它们故意缺乏 time zone (中的名称 Continent/Region 格式)或 offset-from-UTC (小时分秒数)。

    这个 ZoneId 类表示时区。

    我在用这个词 Unzoned 以提醒我们这些值 表示时间线上的实际时刻。“本地”这个词往往会让初学者感到困惑。

    public class Flight {
        private String flightNumber;
        private LocalDate departureDateUnzoned;
        private LocalTime departureTimeUnzoned;
        private ZoneId departureZoneId ;
    }
    

    对于到达,存储该航班的预期时间跨度,而不是到达日期时间。您可以计算到达时间,因此无需存储它。这个 Duration 类跟踪小时、分钟、秒和分数秒的数量。

    要计算到达时间,让我们使用 LocalDateTime 类,它只是将 本地日期 使用 当地时间 .我们可以用这种类型制作一个 departureUnzoned 类定义中的成员变量。我单独去了 本地日期 当地时间 作为构建块,以便您了解各个部分。许多程序员使用他们的直觉而不是文档来假设 LocalDateTime 表示某个位置的特定时刻,而实际上它的含义正好相反。(在堆栈溢出建议中,您会发现许多错误答案 LocalDateTime 实际上什么时候 Instant ZonedDateTime 应使用。)

    让我们添加一个方法来计算到达时间。

    public class Flight {
        private String flightNumber;
        private LocalDate departureDateUnzoned;
        private LocalTime departureTimeUnzoned;
        private ZoneId departureZoneId;
        private Duration duration;
    
        public LocalDateTime arrivalDateTimeUnzoned () {
            LocalDateTime departureUnzoned = LocalDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned );
            LocalDateTime ldt = departureUnzoned.plus( this.duration );
            return ldt;
        }
    }
    

    但是这个回来了 LocalDateTime 无法说明时区。通常,航空公司和火车向客户报告调整到该地区时区的预期到达时间。所以我们需要一个到达时区。我们可以在计算到达时使用该区域,从而生成 ZonedDateTime A. 分区DateTime 一个特定的时刻 时间线上的一个点,不像 LocalDateTime 但请记住,如果我们计划未来的航班 分区DateTime 如果我们的代码在政客重新定义时区后运行,将会发生变化。

    public class Flight {
        private String flightNumber;
        private LocalDate departureDateUnzoned;
        private LocalTime departureTimeUnzoned;
        private ZoneId departureZoneId;
        private Duration duration;
        private ZoneId arrivalZoneId;
    
        public ZonedDateTime arrivalDateTimeZoned () {
            ZonedDateTime departureZoned = ZonedDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned , this.departureZoneId );
            ZonedDateTime zdt = departureZoned.plus( this.duration );
            return zdt;
        }
    }
    

    回到问题中关于自动确定日期的部分。这需要一个时区。在任何特定的时刻,全球各地的日期都不尽相同。想想看。午夜过后的几分钟,法国巴黎迎来了新的一天,而魁北克蒙特勒州仍然是昨天。

    我们可以询问JVM当前的默认时区。

    ZoneId userZoneId = ZoneId.systemDefault() ;
    

    但在关键时刻,您必须与用户确认。

    ZoneId userZoneId = ZoneId.of( "America/Montreal" ) ; 
    

    现在我们可以添加您要求的构造函数,通过一天中的时间(a 当地时间 ,并使用JVM的当前默认值猜测时区。

    但我们还需要所有其他的零件。因此,默认日期并不能为我们节省很多。

    public class Flight {
        private String flightNumber;
        private LocalDate departureDateUnzoned;
        private LocalTime departureTimeUnzoned;
        private ZoneId departureZoneId;
        private Duration duration;
        private ZoneId arrivalZoneId;
    
        // Constructor
        public Flight ( String flightNumber , LocalTime departureTimeUnzoned , ZoneId departureZoneId , Duration duration , ZoneId arrivalZoneId ) {
            this.flightNumber = flightNumber;
            this.departureTimeUnzoned = departureTimeUnzoned;
            this.departureZoneId = departureZoneId;
            this.duration = duration;
            this.arrivalZoneId = arrivalZoneId;
    
            // Determine today’s date using JVM’s current default time zone. Not advisable in many business scenarios, but specified by our Question at hand.
            ZoneId z = ZoneId.systemDefault();
            LocalDate today = LocalDate.now( z );
            this.departureDateUnzoned = today;
        }
    
        public ZonedDateTime arrivalDateTimeZoned () {
            ZonedDateTime departureZoned = ZonedDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned , this.departureZoneId );
            ZonedDateTime zdt = departureZoned.plus( this.duration );
            return zdt;
        }
    }
    

    让我们添加 toString 报告方法。

    在标准中,我们将日期时间值表示为字符串 ISO 8601 格式。这个 JAVA时间 类在解析/生成字符串时使用这些标准格式。这个 Z 结尾处发音 Zulu 和方法 UTC

    虽然航空公司和火车在地区时区向其客户报告日期时间,但我们可以假设他们在内部只使用UTC。这个 Instant 类具体表示UTC中的值。所以我们 toString公司 摘录 瞬间 中的对象 分区DateTime 对象。

    我们添加了一个 main 演示方法。这是完整的课程 import

    package com.basilbourque.example;
    
    import java.time.*;
    
    public class Flight {
        private String flightNumber;
        private LocalDate departureDateUnzoned;
        private LocalTime departureTimeUnzoned;
        private ZoneId departureZoneId;
        private Duration duration;
        private ZoneId arrivalZoneId;
    
        // Constructor
        public Flight ( String flightNumber , LocalTime departureTimeUnzoned , ZoneId departureZoneId , Duration duration , ZoneId arrivalZoneId ) {
            this.flightNumber = flightNumber;
            this.departureTimeUnzoned = departureTimeUnzoned;
            this.departureZoneId = departureZoneId;
            this.duration = duration;
            this.arrivalZoneId = arrivalZoneId;
    
            // Determine today’s date using JVM’s current default time zone. Not advisable in many business scenarios, but specified by our Question at hand.
            ZoneId z = ZoneId.systemDefault();
            LocalDate today = LocalDate.now( z );
            this.departureDateUnzoned = today;
        }
    
        public ZonedDateTime arrivalDateTimeZoned () {
            ZonedDateTime departureZoned = ZonedDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned , this.departureZoneId );
            ZonedDateTime zdt = departureZoned.plus( this.duration );
            return zdt;
        }
    
        @Override
        public String toString () {
            ZonedDateTime departureZoned = ZonedDateTime.of( this.departureDateUnzoned , this.departureTimeUnzoned , this.departureZoneId );
            String flightInUtc = departureZoned.toInstant().toString() + "/" + this.arrivalDateTimeZoned().toInstant().toString();
            return "Flight{ " +
                    "flightNumber='" + this.flightNumber + '\'' +
                    " | departureDateUnzoned=" + this.departureDateUnzoned +
                    " | departureTimeUnzoned=" + this.departureTimeUnzoned +
                    " | departureZoneId=" + this.departureZoneId +
                    " | departureZoned=" + departureZoned +
                    " | duration=" + this.duration +
                    " | arrivalZoneId=" + this.arrivalZoneId +
                    " | calculatedArrival=" + this.arrivalDateTimeZoned() +
                    " | flightInUtc=" + flightInUtc +
                    " }";
        }
    
        public static void main ( String[] args ) {
            LocalTime lt = LocalTime.of( 6 , 0 ); // 6 AM.
            Flight f = new Flight( "A472" , lt , ZoneId.of( "America/Los_Angeles" ) , Duration.parse( "PT6H37M" ) , ZoneId.of( "America/Montreal" ) );
            String output = f.toString();
            System.out.println( output );
        }
    }
    

    运行时。

    航班{flightNumber='A472'|出发日期未分区=2018-05-06 |出发时间未分区=06:00 |出发区域ID=美国/洛杉矶|出发区域ID=2018-05-06T06:00-07:00[美国/洛杉矶]|持续时间=PT6H37M |抵达区域ID=美国/蒙特利尔|计算到达时间=2018-05-06T12:37-07:00[美国/洛杉矶]|飞行TC=2018-05-INUINU 06T13:00:00Z/2018-05-06T19:37:00Z}

    要从控制台使用此功能,请询问用户24小时制的时间。分析输入字符串。

    String input = "14:56" ;  // 24-hour clock.
    LocalTime lt = LocalTime.parse( input ) ;
    

    对于现实世界的工作来说,这还远远不够。但希望它能成为一个有教育意义的例子。


    关于 JAVA时间

    这个 java.time 框架内置于Java 8及更高版本中。这些课程取代了烦人的旧课程 legacy 日期时间类,如 java.util.Date ,则, Calendar ,& SimpleDateFormat

    这个 Joda时间 项目,现在处于 maintenance mode ,建议迁移到 java.time 课程。

    要了解更多信息,请参阅 Oracle Tutorial 。并搜索堆栈溢出以获取许多示例和解释。规格为 JSR 310

    您可以交换 JAVA时间 对象直接与数据库连接。使用 JDBC driver 符合 JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 课程。

    从何处获取java。时间课程?

    这个 ThreeTen-Extra project扩展了java。额外上课的时间。该项目是java未来可能添加内容的试验场。时间您可以在这里找到一些有用的类,例如 Interval ,则, YearWeek ,则, YearQuarter more