Java中的Date

为什么用类表示日期,而不是像其他语言中那样用一个内置(built-in)类型来表示?例如,Visual Basic 中有一个内置的 date 类型,程序员可以采用#12/31/1999格式指定日期。看起来这似乎很方便,程序员只需要使用内置的 date 类型而不用考虑类。但实际上,VisualBasic 这样设计合适吗?在有些地区,日期表示为月日/年,而另外一些地区则表示为日1月/年。语言设计者是否能够预见这些问题呢?如果没有处理好这类问题,语言就有可能陷入混乱,对此感到不满的程序员也会丧失使用这种语言的热情。如果使用类,这些设计任务就交给了类库的设计者。如果类设计得不完善,那么其他程序员可以很容易地编写自己的类,改进或替代(replace)这些系统类(作为印证:Java的日期类库开始时有些混乱,现在已经重新设计了两次)。

System.out.println(new Date());这个表达式会构造一个新对象啊你个,这个对象初始化为当前的日期和时间。image-20240926194346958

或者可以对刚构造的对象应用一个方法。Date类中有一个toString的方法。这个方法将生成日期的一个字符串描述。image-20240926194605240

在这两个例子中,构造的对象只使用了一次。通常,可能希望保留所构造的现象从而能继续使用,为此我们把对象存放在一个变量里Date rightnow = new Date(),rightnow引用了新构造的对象

image-20240926201214554

对象和对象变量之间存在着一个重要的区别

Date startTime定义了一个对象变量startTime,它可以引用Date类型的对象。但是,一定要认识到它不是一个对象,而且实际上它没有引用任何对象。所以无法调用startTime.toString()方法。所以必须首先初始化startTime变量,可以写成startTime = rightnow或者startTime = new Date(),这两种写法都引用了同一个对象image-20240926202640117

要认识到重要的一点:对象变量并不实际包含一个对象,它只是引用一个对象。在Java中,任何对象变量的值都是一个引用,指向存储在另外一个地方的某个对象。new 操作符的返回值也是一个引用。下面的语句:
Date startTime =new Date();有两个部分。表达式new Date()构造了一个Date类型的对象,它的值是新创建对象的一个引用。再将这个引用存储在 startTime 变量中。
可以显式地将对象变量设置为null,指示这个对象变量目前没有引用任何对象。image-20240926203001884

Java的对象变量虽然引用了对象,但是C++中没有null作用,而且引用不能赋值。应当把对象变量看作是类似于C++的对象指针,例如:
Date rightNow; // Java
实际上等同于
Date* rightNow; //C++
一旦建立了这种关联,一切就清楚了。当然,只有使用了new调用后Date * 指针才会初始化。就这一点而言,C++与 Java的语法儿乎是一样的。
Date* rightNow= new Date();//C++
如果把一个变量复制到另一个变量,两个变量就指向同一个日期,即它们是同一个对象的指针。Java中的null引用对应于C+中的NULL指针。
所有的Java对象都存储在堆中。当一个对象包含另一个对象变量时,它只是包含另一个堆对象的指针。
在C++中,指针十分令人头疼,因为它们很容易出错。稍不小心就会创建一个错误的指针,或者使内存管理出问题。在Java语言中,这些问题都不复存在。如果使用一个没有初始化的指针,那么运行时系统将会产生一个行时错误,而不是生成随机的结果。另外,你不必担心内存管理问题,垃圾回收器会处理相关的事宜。
C++确实做了很大的努力,它通过支持复制构造器和赋值送算符来实现对象的自动复制。例如,一个链表(linked list)的副本是一个新链表,其内客与原始链表相同但是有一组独立的链接。这样一来就可以适当地设计类,使它们与内置类型有相同的复制行为。在Java中,必须使用cone方法获得一个对象的完整副本。

LocalDate类

Java的时间是用距离一个固定时间点的毫秒数表示的,这个时间就是所谓

的纪元。它是UTC时间1970年1月1日00:00:00。UTC就是Coordinated Universal Time国际协调时间。

类库设计者决定将保存时间与给时间点命名分开。所以,标准Java类库分别包含了两个类:一个是用来表示时间点的 Date 类;另一个是用大家熟悉的日历表示法表示日期的 LocalDate类。Java8引人了另外一些类来处理日期和时间的不同方面--有关内容参见卷Ⅱ第6章。
将时间度量与日历分开是一种很好的面向对象设计。通常,最好使用不同的类表示不同的概念。
不要使用构造器来构造LocalDate类的对象。实际上,应当使用静态工厂方法(factorymethod),它会代表你调用构造器。下面的表达式:
LocalDate.now()会构造一个新对象,表示构造这个对象时的日期。
可以提供年、月和日来构造对应一个特定日期的对象:
LocalDate.of(1999,12,31)
当然,通常我们都希望将构造的对象保存在一个对象变量中:
LocalDate newYearsEve = LocalDate.of(1999, 12,31);
一旦有了一个 LocalDate对象,可以用方法getYear、getMonthValue和getDay0fMonth 得到年月和日:

image-20240926204551314

如果在向未来定一个时刻,比如增加1000天来计算是哪一天,我们可以使用plusday方法image-20240926204801966

Java库的一个比较早的版本曾经有过另一个处理日历的类,名为GregorianCalendar

GregorianCalendar someday = new GregorianCalendar(2000, 1, 27);
someday.add(Calendar.DAY_OF_MONTH, 1000);
int year = someday.get(Calendar.YEAR);
int month = someday.get(Calendar.MONTH);
int day = someday.get(Calendar.DAY_OF_MONTH);

image-20240926205600364

Eg:打印当月日历

import java.time.DayOfWeek;
import java.time.LocalDate;

public class Main {
    public static void main(String[] args) {
        LocalDate date = LocalDate.now(); //首先构造一个对象,并用当前日期初始化
        //获取当前月日
        int month = date.getMonthValue();
        int today = date.getDayOfMonth();
        date = date.minusDays(today - 1);// 讲日期设置为当月第一天
        DayOfWeek weekday = date.getDayOfWeek();//并得到这一天是星期几

        int value = weekday.getValue();// 1=Monday,...,7= Sunday
        System.out.println("Mon Tue Wed Thu Fri Sat Sun");
        for (int i = 1; i < value; i++)
            System.out.print("    ");
        while (date.getMonthValue() == month) {
            System.out.printf("%3d", date.getDayOfMonth());
            if (date.getDayOfMonth() == today) {
                System.out.print("*");
            } else {
                System.out.print(" ");
            }
            date = date.plusDays(1);
            if (date.getDayOfWeek().getValue() == 1)
                System.out.println();

        }
        if (date.getDayOfWeek().getValue() != 1)
            System.out.println();

    }
}

image-20240929172508929