Java 基础学习(十二)文本I/O、日期与时间API

news2024/9/20 15:05:45

1 文本 I/O

1.1 字符流

1.1.1 什么是字符流

在Java中,字符流是指提供了基于字符的I/O能力的API。

Java 1.0中提供的基于字节的I/O流API只能支持8位字节流,无法妥善地处理16位Unicode字符。由于需要支持Unicode处理国际化字符,因此Java 1.1 对基础流式I/O库进行了重大的修改,核心是增加了字符流相关的API,处理国际化Unicode字符的编码和解码。

字符流是以字符(char)为单位读写数据的:一次处理一个 Unicode。字符流的底层仍然是基本的字节流,它封装了字符的编码解码算法。

字符流以Reader和Writer为核心抽象类,所有的字符输入流类均继承Reader,所有的字符输出流均继承Writer。如下图所示:

 

字符流相关子类可以分为节点流和处理流:上图中带阴影的是节点流,不带阴影的是处理流。

1.1.2 【案例】FileWriter示例

编写代码,使用FileWriter将字符写入文件。代码示意如下:

package api_04;
import java.io.FileWriter;
import java.io.Writer;
public class WriterDemo1 {
    public static void main(String[] args){
        Writer writer = null;
        try{
            writer = new FileWriter("./src/api_04/demo");
            writer.write("Hello World!\n");
            writer.write("Hello FileWriter!\n");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (writer != null){
                try{
                    writer.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
}

1.1.3 【案例】FileReader示例

编写代码,使用FileReader从文件中读取字符。代码示意如下:

package api_04;
import java.io.FileReader;
import java.io.Reader;
public class ReaderDemo1 {
    public static void main(String[] args) {
        Reader reader = null;
        try{
            reader = new FileReader("./src/api_04/demo");
            char[] data = new char[5];
            int len = 0;
            while (len !=-1){
                System.out.print(new String(data,0,len));
                len = reader.read(data);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (reader != null){
                try{
                    reader.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
}

1.1.4 try-with-resources语法

在前面的案例中,为了妥善的处理I/O操作中可能出现的异常,并保证在程序结束后关流,我们使用了try-catch-finally语句块。但在实际编码中遇到很多不方便的情况,例如:

  • finally语句块不能访问try语句块中声明的变量
  • finally语句块中需要再次添加try-catch语句块

幸好Java 7 引入了try-with-resources语法,可以很好地简化上述代码。

 

这种称为try-with-resources语法。其要求为:

1、try后面的括号称为资源说明头,用于创建语句块中使用的资源对象

2、资源说明头中创建的对象必须实现java.lang.AutoCloseable接口,该接口只有一个方法-close()

3、资源说明头中可以包含多个创建对象的语句,用分号隔开,最后的分号可以省略

4、不论如何退出try语句块,都会自动调用所有资源对象的close方法

5、退出try语句块时,会以与声明资源对象相反的顺序去调用资源对象的close方法

1.1.5 【案例】try-with-resources示例

编写代码,测试try-with-resources的用法。代码示意如下:

package api_04;
import java.io.Closeable;
import java.io.IOException;
public class TWRDemo {
    public static void main(String[] args) {
        try(
            MyStream1 stream1 = new MyStream1();
            MyStream2 stream2 = new MyStream2();
        ){
            System.out.println("try...");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
class MyStream1 implements Closeable{
    @Override
    public void close() throws IOException {
        System.out.println("MyStream1 close...");
    }
}
class MyStream2 implements Closeable{
    @Override
    public void close() throws IOException {
        System.out.println("MyStream2 close...");
    }
}

1.2 字符缓冲流

1.2.1 字符缓冲流概述

BufferedReader和BufferedWriter分别是字符输入流和字符输出流对应的缓冲流,内置了缓冲区,通过缓冲区来减少实际的物理读写操作,进而提高读写效率。这两个类默认的缓冲区大小均为8192个字符,并支持通过构造器来设置缓冲区大小。

BufferedReader中还提供了一些增强的I/O操作方法,例如:

  • readLine:读取文本中的一行内容,以'\n','\r'来识别,返回的内容不包含换行符
  • skip:跳过指定数量的字符

BufferedWriter中没有提供相似的writeLine方法,但是提供了newLine方法,调用时可以向流中输出一个换行符,以达到换行的效果。

1.2.2 【案例】BufferedWriter示例

编写代码,测试BufferedWriter的用法。代码示意如下:

package api_04;
import java.io.*;
public class BufferedWriterDemo {
    public static void main(String[] args) {
        try(
            Writer writer = new FileWriter("./src/api_04/demo2");
            BufferedWriter bufferedWriter = new BufferedWriter(writer);
        ){
            bufferedWriter.write("Hello world!");
            bufferedWriter.newLine();
            bufferedWriter.write("Hello BufferedWriter!");
            bufferedWriter.newLine();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

1.2.3 【案例】BufferedReader示例

编写代码,测试BufferedReader的用法。代码示意如下:

package api_04;
import java.io.*;
public class BufferedReaderDemo {
    public static void main(String[] args) {
        try(
            Reader reader = new FileReader("./src/api_04/demo2");
            BufferedReader bufferedReader = new BufferedReader(reader);
        ){
            String line = bufferedReader.readLine();
            while (line!=null) {
                System.out.println(line);
                line = bufferedReader.readLine();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

1.3 转换流

1.3.1 转换流概述

转换流用于实现字节流和字符流之间的转换。

InputStreamReader是字节输入流到字符输入流的桥梁,用于将InputStream转换为Reader,可以读取字节数据并根据指定的字符集转换为字符数据。

OutputStreamWriter是字符输出流到字节输出流的桥梁,用于将OutputStream转换为Writer,可以根据指定的字符集将写出的字符数据转换为字节数据。

1.3.2 指定字符编码

InputStreamReader 的构造方法允许设置字符集

  • InputStreamReader(InputStream in,String charsetName):基于给定的字节输入流以及字符编码创建
  • InputStreamReader(InputStream in):该构造方法会根据系统默认字符集创建

OutputStreamWriter 的构造方法:

  • OutputStreamWriter(OutputStream out,String charsetName):基于给定的字节输出流以及字符编码创建
  • OutputStreamWriter(OutputStream out):该构造方法会根据系统默认字符集创建

1.3.3 【案例】OutputStreamWriter示例

编写代码,测试OutputStreamWriter的用法,并指定字符编码。代码示意如下:

package api_04;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class OutputStreamWriterDemo {
    public static void main(String[] args) {
        try(
            FileOutputStream fos
                        = new FileOutputStream("./src/api_04/demo3");
            OutputStreamWriter osw
                        = new OutputStreamWriter(fos,"utf-8");
            BufferedWriter bw = new BufferedWriter(osw)
        ){
            bw.write("世界你好!");
            bw.newLine();
            bw.write("转换流你好!");
            bw.newLine();
            System.out.println("写出完毕!");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

1.3.4 【案例】InputStreamReader示例

编写代码,测试InputStreamReader的用法,并指定字符编码。代码示意如下:

package api_04;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class InputStreamReaderDemo {
    public static void main(String[] args) {
        try(
            FileInputStream fis
                        = new FileInputStream("./src/api_04/demo3");
            InputStreamReader isr
                        = new InputStreamReader(fis,"utf-8");
            BufferedReader br = new BufferedReader(isr);
        ){
            String line =br.readLine();
            while(line!=null){
                System.out.println(line);
                line = br.readLine();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

1.3.5 【案例】数据统计示例

掌握了I/O相关API后,可以结合之前所学的Java基础知识,实现基础的数据统计操作。

weather_data_ny_201906.csv文件是某气象网站提供的纽约市2019年6月的天气数据。文件内容如下图所示:

 现有如下需求:

1、数据预处理:提取weather_data_ny_201906.csv文件中的"STATION","DATE","MAX"三列的值,写入新的文件data1.csv,新文件中需要表头行,的数据继续使用英文逗号分隔,但是数据前后不再包含双引号。data1.csv文件如下图所示:

 2、基于data1.csv,统计每个站点的6月平均温度,结果四舍五入保留小数点后2位,写入data2.csv,data2.csv文件的表头为"STATION", "AVG"。data2.csv文件如下图所示:

 代码示意如下:

package api_04;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class DataPreProcessDemo {
    public static void main(String[] args) {
        try(
                FileReader fr =new FileReader("./src/api_04/weather_data_ny_201906.csv");
                BufferedReader br =new BufferedReader(fr);
                FileWriter fw =new FileWriter("./src/api_04/data1.csv");
                BufferedWriter bw =new BufferedWriter(fw)
        ){
            // 写出第一行表头行
            bw.write("STATION,DATE,MAX");
            // 读取数据
            String line =br.readLine(); // 表头行,需跳过
            line = br.readLine(); // 第一行数据
            while(line!=null){
                StringBuilder builder = new StringBuilder();
                // 处理数据
                String[] dataArray = line.replaceFirst("\"","") // 去掉首个字符串
                                            .split("\",\""); // 使用","切分为字符串数组
                builder.append(dataArray[0].trim()).append(",") // 拼接STATION列
                        .append(dataArray[5].trim()).append(",") // 拼接DATE列
                        .append(dataArray[9].trim());
                // 写出一行新数据行
                bw.newLine();
                bw.write(builder.toString());
                // 读取一行新的数据
                line = br.readLine();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
package api_04;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class StatisticsDemo {
    public static void main(String[] args) {
        try(
                FileReader fr =new FileReader("./src/api_04/data1.csv");
                BufferedReader br =new BufferedReader(fr);
                FileWriter fw =new FileWriter("./src/api_04/data2.csv");
                BufferedWriter bw =new BufferedWriter(fw)
        ){
            // 写出第一行表头行
            bw.write("STATION,AVG");
            /*
             * 处理数据思路:
             * 分组求均值,按STATION分组,求组内均值
             * 共5个站点,分5组
             * 需要过滤掉非6月的数据
             */
            // 存储各个站点的温度和,站点id和数组下标对应关系
            // 99727199999-0, 72505394728-1, 72055399999-2,
            // 99774399999-3, 72503014732-4
            BigDecimal[] tempDataArray = new BigDecimal[5];
            for(int i =0; i < tempDataArray.length; i++){
                tempDataArray[i]=new BigDecimal(0);
            }
            int[] dataCount = new int[5]; // 统计数据条数
            String[] stationArray = new String[]
                    {"99727199999", "72505394728", "72055399999"
                            ,"99774399999","72503014732"};
            // 读取数据
            String line =br.readLine(); // 表头行,需跳过
            line = br.readLine(); // 第一行数据
            while(line!=null){
                // 处理数据
                String[] dataArray = line.split(",");
                // 过滤非6月数据
                if (!dataArray[1].startsWith("2019-06")){
                    line=br.readLine();
                    continue; // 不处理该行数据
                }
                BigDecimal temp = new BigDecimal(dataArray[2]);
                switch (dataArray[0]){
                    case "99727199999":
                        tempDataArray[0] = tempDataArray[0].add(temp);
                        dataCount[0] = dataCount[0] + 1;
                        break;
                    case "72505394728":
                        tempDataArray[1] = tempDataArray[1].add(temp);
                        dataCount[1] = dataCount[1] + 1;
                        break;
                    case "72055399999":
                        tempDataArray[2] = tempDataArray[2].add(temp);
                        dataCount[2] = dataCount[2] + 1;
                        break;
                    case "99774399999":
                        tempDataArray[3] = tempDataArray[3].add(temp);
                        dataCount[3] = dataCount[3] + 1;
                        break;
                    case "72503014732":
                        tempDataArray[4] = tempDataArray[4].add(temp);
                        dataCount[4] = dataCount[4] + 1;
                        break;
                    default:
                        System.out.println("站点名称未匹配:"+dataArray[0]);
                        break;
                }
                // 读取一行新的数据
                line = br.readLine();
            }
            // 求均值
            for(int i=0;i < tempDataArray.length;i++) {
                BigDecimal avg = tempDataArray[i]
                        .divide(new BigDecimal(dataCount[i]),2, RoundingMode.HALF_UP);
                StringBuilder builder = new StringBuilder();
                builder.append(stationArray[i]).append(",").append(avg);
                // 写出一行新数据行
                bw.newLine();
                bw.write(builder.toString());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

2 日期与时间API

2.1 Date类

2.1.1 Java中的日期时间

日期和时间在应用程序中具有非常广泛和多样的应用,包括日期时间数据的获取和封装、日期时间数据的计算,以及日期时间数据的时区转换和格式转换等多个方面。

  • 大部分的应用程序都有日志模块,记录应用运行过程中的程序的执行情况和用户的各类操作
  • 一些特定的功能会用到计时器功能,如订单的支付限时为15分钟
  • 通过用户的生日和当前日期计算用户的年龄
  • 通过用户的登录时间和当前时间计算用户在线时长等
  • 一些面向国际化的应用程序也存在日期时间数据的时区转换和格式转换的需求

Java中提供了多种日期时间相关的工具类和丰富的API,使开发者可以简化日期时间操作,以提高应用程序的开发效率。

2.1.2 纪元(Epoch)

在计算机领域,“纪元”是计算机测量系统时间的日期和时间。大多数计算机系统将时间确定为一个数字,表示从特定的任意日期和时间以来经过的秒数。 例如,Unix和POSIX将时间测量为自1970年1月1日00:00:00 GMT 以来经过的秒数,该时间点称为 Unix“纪元”。

由于我国处于东八区,因此基准时间为1970年1月1日8时0分0秒。北京时间2023年1月1日凌晨可以表示为1672502400。

这种用于表示日期和时间的数字就是在开发中广泛使用的时间戳(Timestamp),常有精确到秒和精确到毫秒2种表示形式。

Java中使用的时间戳支持精确到秒、毫秒和纳秒,之前在统计程序运行效率中使用的System.currentTimeMillis()方法,就是返回当前的毫秒级时间戳。

2.1.3 Date类

java.util.Date类封装日期和时间信息,表示一个特定瞬间的类,时间可以精确到毫秒。Date的每一个实例用于表示一个时间,内部维护一个long值,该值保存的是自标准基准时间以来的毫秒数。

Date类是Java中使用最为广泛的一个日期时间类之一。

由于设计问题,该类中的很多方法已被标记过时,使用时应注意避免。查看下图:

 

这种已经被标记过时的方法,应尽量避免使用。

2.1.4【案例】Date类示例

编写代码,测试Date类的用法。代码示意如下:

package api_04;
import java.util.Date;
public class DateDemo {
    public static void main(String[] args) {
        Date now = new Date();
        System.out.println(now);
        // Date大部分方法都过时了
        // now.getYear();
        /*
         * 获取Date内部维护的毫秒值
         */
        long time = now.getTime();
        System.out.println(time);
        /*
         * 设置一个毫秒使当前Date表示该时间
         */
        now.setTime(0);
        System.out.println(now);
    }
} 

2.2 SimpleDateFormat类

2.2.1 DateFormat 类概述

在输出Date对象代表的时间时,会自动调用Date类中的toString()方法。Date类对Object类中的toString()方法进行了重写,按照“dow mon dd hh:mm:ss zzz yyyy”(星期 月份 日期 小时:分钟:秒 时区 年份)的格式输出该Date对象代表的时间。在很多应用中,开发者需要指定自定义的时间输出格式。Java中提供的java.text.DateFormat用来满足开发者对日期时间格式化的需求。

DateFormat是日期/时间格式化子类的抽象类,通过这个类可以完成日期和文本之间的转换。DateFormat类支持日期的格式化(日期→文本)、日期的解析(文本→日期)和日期的规范化。

DateFormat为抽象类,不能直接使用。在实际开发中,比较常用的是DateFormat类的子类——SimpleDateFormat。

2.2.2 SimpleDateFormat 类

SimpleDateFormat类的构造方法:

  • SimpleDateFormat( )
  • SimpleDateFormat(String pattern):用给定的日期时间格式pattern构造SimpleDateFormat对象

参数pattern是一个字符串,代表日期时间的自定义格式,常用的格式为“yyyy-MM-dd HH:mm:ss”,其中,yyyy表示年份,MM表示月份,dd表示日期,HH表示小时,mm表示分钟,ss表示秒。

SimpleDateFormat的常用方法:

  • String format(Date date):将 Date 对象代表的时间格式化为字符串
  • Date parse(String source):将字符串解析为 Date 对象

2.2.3 日期模式匹配字符

日期模式匹配字符如下表所示:

 

2.2.4【案例】日期格式化示例

编写代码,测试日期格式化输出。代码示意如下:

package api_04;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatDemo1 {
    public static void main(String[] args) {
        Date now = new Date();
        System.out.println(now);
        /*
         * yyyy-MM-dd HH:mm:ss
         */
        SimpleDateFormat sdf
                = new SimpleDateFormat(
                "yyyy-MM-dd HH:mm:ss a E");
        /*
         * String format(Date date)
         * 将给定的Date按照当前SDF指定的日期
         * 格式转换为字符串
         */
        String line = sdf.format(now);
        System.out.println(line);
    }
}

2.3 Java 8 新日期时间类

2.3.1新日期时间类概述

从Java 8开始,java.time包提供了新的日期和时间API,主要涉及的类型有:

  • 本地日期和时间:LocalDateTime,LocalDate,LocalTime
  • 带时区的日期和时间:ZonedDateTime
  • 时刻:Instant
  • 时区:ZoneId,ZoneOffset
  • 时间间隔:Duration

以及一套新的用于取代SimpleDateFormat的格式化类型DateTimeFormatter。

和旧的API相比,新API严格区分了时刻、本地日期、本地时间和带时区的日期时间,并且,对日期和时间进行运算更加方便。

此外,新API修正了旧API不合理的常量设计:

  • Month的范围用1~12表示1月到12月
  • Week的范围用1~7表示周一到周日

2.3.2本地化日期时间 API

在很多本地化的应用中,考虑时区是没有必要的。Java 8在java.time包中提供了简化版的日期时间操作类,包括LocalDate、LocalTime和LocalDateTime。

  • LocalDate表示本地日期
  • LocalTime表示本地时间
  • LocalDateTime可以看成前两者的组合,表示本地日期和时间

2.3.3【案例】LocalDateTime示例

编写代码,测试LocalDateTime。代码示意如下:

package api_04;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class LocalDateTimeDemo {
    public static void main(String[] args) {
        System.out.println("-------------构建LocalDateTime对象-------------");
        // 获取当前时间的ldt对象
        LocalDateTime ldt1 = LocalDateTime.now();
        System.out.println("ldt1:\t"+ldt1);
        // 获取表示指定时间的ldt对象
        LocalDateTime ldt2 = LocalDateTime.of(2022,9,18,22,0,0,0);
        System.out.println("ldt2:\t"+ldt2);
        System.out.println("-------------获取日期时间信息方法-------------");
        System.out.println(ldt1.getYear()+":"+ldt1.getMonthValue()
                +":"+ldt1.getDayOfMonth());
        System.out.println(ldt1.getHour()+":"+ldt1.getMinute()
                +":"+ldt1.getSecond());
        System.out.println("-------------日期时间计算方法-------------");
        LocalDateTime ldt3 = ldt1.plus(6, ChronoUnit.HOURS)
                .plusMinutes(10);
        System.out.println("ldt3:\t"+ldt3);
        LocalDateTime ldt4 = ldt1.minus(1, ChronoUnit.HOURS)
                .minusMonths(1);
        System.out.println("ldt4:\t"+ldt4);
    }
}

2.3.4【案例】ZonedDateTime示例

编写代码,测试ZonedDateTime。代码示意如下:

package api_04;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class ZonedDateTimeDemo {
    public static void main(String[] args) {
        // 直接创建ZonedDateTime对象
        ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区
        // 用指定时区获取当前时间
        ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));
        System.out.println(zbj);
        System.out.println(zny);
        // 通过LocalDateTime转换
        LocalDateTime ldt = LocalDateTime.of(2023, 1, 2, 8, 15, 33);
        ZonedDateTime zdt1 = ldt.atZone(ZoneId.systemDefault());
        ZonedDateTime zdt2 = ldt.atZone(ZoneId.of("America/New_York"));
        System.out.println(zdt1);
        System.out.println(zdt2);
        // 时区转换
        // 以中国时区获取当前时间:
        ZonedDateTime zdt3 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
        // 转换为巴黎时间:
        ZonedDateTime zdt4 = zbj.withZoneSameInstant(ZoneId.of("Europe/Paris"));
        System.out.println(zdt3);
        System.out.println(zdt4);
    }
}

2.3.5【案例】DateTimeFormatter示例

编写代码,测试DateTimeFormatter。代码示意如下:

package api_04;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class DateTimeFormatterDemo {
    public static void main(String[] args) {
        ZonedDateTime zdt = ZonedDateTime.now();
        // 日期格式化
        DateTimeFormatter formatter1 =
                DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm ZZZZ");
        System.out.println(formatter1.format(zdt));
        DateTimeFormatter formatter2 =
                DateTimeFormatter.ofPattern("yyyy MMM dd EE HH:mm", Locale.CHINA);
        System.out.println(formatter2.format(zdt));
        DateTimeFormatter formatter3 =
                DateTimeFormatter.ofPattern("E, MMMM/dd/yyyy HH:mm", Locale.US);
        System.out.println(formatter3.format(zdt));
        // 字符串转时间
        DateTimeFormatter formatter4 =
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String time = "2020-05-12 20:13:15";
        LocalDateTime ldt = LocalDateTime.parse(time,formatter4);
        System.out.println(ldt);
    }
} 

2.3.6【案例】Instant示例

编写代码,测试Instant。代码示意如下:

public class InstantDemo {
    public static void main(String[] args) {
        // 获取当前时间对象
        Instant i1 = Instant.now();
        // 输出当前时间,默认使用零时区
        System.out.println("defalut:\t"+i1);
        // 获取时间戳
        System.out.println("timestamp:\t"+i1.getEpochSecond());
        System.out.println("timestamp:\t"+i1.toEpochMilli());
        // 通过Clock的API获取东八区对应的时钟
        Clock offsetClock = Clock.offset(Clock.systemUTC(),
                Duration.ofHours(8));
        // 获取当前时间对象,设置使用东八区时钟
        Instant i2 = Instant.now(offsetClock);
        // 输出当前时间
        System.out.println("UTC+8:\t \t "+i2);
        // 基于指定时间获取Instant对象
        Instant i3 = Instant.ofEpochSecond(i1.getEpochSecond()
                -3600);
        System.out.println("one hour ago:\t "+i3);
        // 基于字符串获取Instant对象
        Instant i4 = Instant.parse("2022-09-18T06:00:00Z");
        System.out.println("from String:\t "+i4);
        // Instant相关操作
        Instant i5 = Instant.parse("2022-09-18T06:00:00Z");
        System.out.println("i1:\t\t"+i1);
        // 时间的加法运算
        Instant i6 = i1.plus(3L, ChronoUnit.HOURS);
        System.out.println("i1+3 hour:\t"+i2);
        // 时间的减法运算
        Instant i7 = i1.minus(5L,ChronoUnit.HOURS);
        System.out.println("i1-5 hour:\t"+i3);
        // 两个时间的差值
        System.out.println("i1-i2 in seconds:"
                +i1.until(i2,ChronoUnit.SECONDS));
        // 判断时间先后
        System.out.println("i1 is before i2:"+i1.isBefore(i2));
        System.out.println("i1 is after i2:"+i1.isAfter(i2));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1316892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络安全——Iptables防DDoS攻击实验

一、实验目的要求&#xff1a; 二、实验设备与环境&#xff1a; 三、实验原理&#xff1a; 四、实验步骤&#xff1a; 五、实验现象、结果记录及整理&#xff1a; 六、分析讨论与思考题解答&#xff1a; 一、实验目的要求&#xff1a; 1、掌握常见DDoS攻击SYN Flood的攻击…

Toyota Programming Contest 2023#8(AtCoder Beginner Contest 333)

A - Three Threes 题目大意&#xff1a;给你一个整数n&#xff0c;将这个数n输出n次。 呃呃 B - Pentagon 题目大意&#xff1a;给你一个正五边形ABCDE&#xff0c;给你任意两条边&#xff0c;判断是否相等 主要问题要判断一下内边&#xff1a;AD&#xff0c;AC&#xff0c;…

小 cookie,大作用:探索网站中的隐私追踪器(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

用Flask搭建简单的web模型部署服务

目录结构如下&#xff1a; 分类模型web部署 classification.py import os import cv2 import numpy as np import onnxruntime from flask import Flask, render_template, request, jsonifyapp Flask(__name__)onnx_session onnxruntime.InferenceSession("mobilen…

【图的应用一:最小生成树】- 用 C 语言实现普里姆算法

目录 一、最小生成树 二、普里姆算法的构造过程 三、普里姆算法的实现 一、最小生成树 假设要在 n 个城市之间建立通信联络网&#xff0c;则连通 n 个城市只需要 n - 1 条线路。这时&#xff0c;自然会考虑这样一个问题&#xff0c;如何在最节省经费的前提下建立这个通信…

云仓酒庄的品牌雷盛红酒分享红酒里加二氧化硫有害吗?

雷盛葡萄酒是广州万豪酒业有限公司旗下主力葡萄酒品牌&#xff0c;该品牌由云仓酒庄负责全国运营。雷盛&#xff08;LEESON&#xff09;品牌系列葡萄酒有幸邀请著名导演张纪中先生担任品牌代言人。采用多国家采购、多葡萄酒品种、多价位区间的全系列整体品牌形式&#xff0c;让…

谷达冠楠科技:抖音网店到底怎么做靠谱

随着互联网的发展&#xff0c;越来越多的人开始尝试在网上开设自己的店铺。而在众多的电商平台中&#xff0c;抖音网店无疑是近年来最受年轻人欢迎的一种方式。那么&#xff0c;抖音网店到底怎么做才能靠谱呢? 首先&#xff0c;我们需要明确一点&#xff0c;无论是在哪个平台上…

JS对象笔记

对象声明 对象也只是一种数据类型/字面值。写对象这个字面值有两种写法&#xff0c;一种是普通的对象&#xff0c;这种对象用new 构造函数&#xff08;&#xff09;&#xff0c;另一种是JS内特有的json对象。这个对象是直接{}就代表对象。且也是在堆内。 对象的构成 无论是上…

Pytorch当中的.detach()操作是什么意思

.detach() 是 PyTorch 中用于从计算图中分离张量的方法。当我们在PyTorch中进行张量运算时&#xff0c;操作会构建一个计算图来跟踪计算历史&#xff0c;这个计算图用于自动求导和反向传播来计算梯度。 使用.detach()方法可以将一个张量从当前的计算图中分离出来&#xff0c;使…

System作为系统进程陔如何关闭?

一、简介 system进程是不可以关闭的&#xff0c;它是用来运行一些系统命令的&#xff0c;比如reboot、shutdown等&#xff0c;以及用来运行一些后台程序&#xff0c;比如ntfs-3g、v4l2loopback等。system进程也被用于运行一些内核模块&#xff0c;比如nvidia、atd等。system进程…

太阳能电池特性测试用太阳光模拟器24H光源

概述 太阳能模拟器是一种在室内模拟太阳光的设备&#xff0c;能够较为准确地模拟太阳辐射的准直性、均匀性和光谱特性。它的基本原理是利用人工光源模拟太阳光辐射&#xff0c;以克服太阳光辐射受环境、时间和气候等因素影响&#xff0c;并且总辐照度不能调节等缺点&#xff0c…

c++ websocket 协议分析与实现

前言 网上有很多第三方库&#xff0c;nopoll,uwebsockets,libwebsockets,都喜欢回调或太复杂&#xff0c;个人只需要在后端用&#xff0c;所以手动写个&#xff1b; 1:环境 ubuntu18 g(支持c11即可) 第三方库:jsoncpp,openssl 2:安装 jsoncpp 读取json 配置文件 用 自动安装 网…

【Redis】远程访问配置教程与远程客户端连接测试

前言 Redis 是一种基于内存的高性能键值存储数据库&#xff0c;常用于缓存、会话管理和实时数据分析等场景。在默认情况下&#xff0c;Redis 不允许远程连接&#xff0c;为了进行远程连接&#xff0c;需要进行一些配置和操作。接下来将介绍如何修改配置文件以允许远程连接&…

毅速:3D打印随形水路 提高良品率和生产效率的新利器

随着科技的不断发展&#xff0c;3D打印技术已经成为模具制造领域的一种重要技术。其中&#xff0c;模具随形水路的设计和制造是提高注塑产品良品率和生产效率的关键环节。 模具随形水路是一种根据产品形状设计的水路&#xff0c;可以更靠近产品&#xff0c;并在模具内热点集中区…

SpringBoot 源码解析2:启动流程1

SpringBoot 源码解析2&#xff1a;启动流程1 1.启动方式2.SpringBootApplication3.SpringApplication3.1 构造器SpringApplication3.2 SpringApplication#run 3.3 SpringApplication#run 中关键方法3.1 SpringApplication#prepareEnvironment3.2 SpringApplication#prepareCont…

前端登录界面网站设计模板--HTML+CSS

🎀登录表单 💖效果展示 💖HTML代码展示 <!DOCTYPE html> <html lang="en" > <head></

【机器学习】044_Kaggle房价预测(机器学习模型实战)

参考自《动手学深度学习》中“Kaggle比赛实战&#xff1a;预测房价”一节 一、数据准备 首先从网站上下载要获取的房价数据。 DATA_HUB是一个字典&#xff0c;用来将数据集名称的字符串和数据集相关的二元组一一对应。 二元组包含两个值&#xff1a;数据集的URL和用来验证文…

网站转换APP源代码 WebAPP源代码 网站生成APP源代码 Flutter项目 带控制端

源码介绍 一款网站转换成APP的源代码,开发语言使用Flutter,开发工具使用的是AndroidStudio,你只需要在APP源代码里面填写你的域名,即可生成即可生成APP,包括安卓或者苹果,与此同时我们提供了APP的控制端.你可以通过控制端设置APP的颜色、添加APP的图标、添加APP的菜单栏目。 …

2020 ICPC·小米邀请赛 决赛 J. Rikka with Book(状压dp)

题目 登录—专业IT笔试面试备考平台_牛客网 n(n<20)本书&#xff0c;放在桌子上&#xff0c; 第i本书的可以看成是li(li<1e3)*1*1的物体&#xff0c;其中长为li&#xff0c;宽为1&#xff0c;高为1&#xff0c; 质量均匀分布&#xff0c;且为wi(wi<1e3) 求n本书摞…