Date 日期时间 浅层研究
若需查看所有函数及属性常量,请直接翻至尾部
获取当前时间の奇怪玩法
Date
new Date().getTime(); //获取当前时间
/**
*@desc 无参构造器调用 System.currentTimeMillis() 传递给有参构造器
*@source java.util.Date.class
*/
public Date() {
this(System.currentTimeMillis());
}
public Date(long date) {
fastTime = date;
}
public long getTime() {
return getTimeImpl();
}
private final long getTimeImpl() {
if (cdate != null && !cdate.isNormalized()) {
normalize(); // 处理时间
}
return fastTime;
}
System
public static native long currentTimeMillis(); // 获取当前毫秒(ms)级时间 (返回从1970年1月1日到现在的总毫秒数)
/*
Returns the current time in milliseconds. Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems
measure time in units of tens of milliseconds.
* 此方法调用时需先切换至系统层执行代码再切换回JVM处理数值,其效率虽大于Java其他封装方法,但在高频率高并发的调用情况下,性能大打折扣。
· 此方法返回的时间受操作系统环境影响
· 比如在Windows上 System.currentTimeMillis()方法并不能提供1ms的计时粒度,它的粒度为15~16ms
· 想要获取更精确的时间可以采用 nanoTime()
*/
public static native long nanoTime(); // 返回当前纳米级(ns)时间值
[^native 原生态方法 使用本地语言实现的功能。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。]:
Calendar
Calendar.getInstance().getTimeInMillis();
/**
*@desc 可以根据系统用户环境获取更准确的 一般时间,但其调用封装过于复杂 效率低,不适合频繁调用或用于精准时间计算
*@source java.util.Calendar
*/
public long getTimeInMillis() {
if (!isTimeSet) {
updateTime();
}
return time;
}
public static Calendar getInstance() //获取日历类实例对象
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT)); //根据系统时区创建
}
奇怪的问题探究区
在空余之时 我做了个测试,发现200次以内 调用 getTimeInMillis() 的时间消耗远小于 200次后,将for循环拆成两份分别累计时间时发现第二次效率明显低于第一次
更有趣的是,单独调用它尽然要比使用 封装类Date的getTime()效率还低
-
查询资料: http://pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.html
查看此资料之前我们需要了解下 native 方法如何实现的与 java 交互
-
SUN公司发布的Java 本地接口(JNI)提供了将Java与C/C++、汇编等本地代码集成的方案,该规范使得在 Java 虚拟机内运行的 Java 代码能够与其它编程语言互相操作,包括创建本地方法、更新Java对象、调用Java方法,引用 Java类,捕捉和抛出异常等,也允许 Java代码调用 C/C++或汇编语言编写的程序和库。
JNI 对应数据类型关系如下表:
Java 类型 |
本地 C 类型 |
实际表示的 C 类型(Win32) |
说明 |
boolean |
jboolean |
unsigned char |
无符号,8 位 |
byte |
jbyte |
signed char |
有符号,8 位 |
char |
jchar |
unsigned short |
无符号,16 位 |
short |
jshort |
short |
有符号,16 位 |
int |
jint |
long |
有符号,32 位 |
long |
jlong |
__int64 |
有符号,64 位 |
float |
jfloat |
float |
32 位 |
double |
jdouble |
double |
64 位 |
void |
void |
N/A |
N/A |
-
//OpenJDK hotspot/src/os/windows/vm/jvm.cpp/os_windows.cpp
jlong os::javaTimeMillis() {
if (UseFakeTimers) {
return fake_time++;
} else {
FILETIME wt;
GetSystemTimeAsFileTime(&wt);
return windows_to_java_time(wt);
}
}
jlong windows_to_java_time(FILETIME wt) {
jlong a = jlong_from(wt.dwHighDateTime, wt.dwLowDateTime);
return (a - offset()) / 10000;
}
static jlong _offset = 116444736000000000;
jlong offset() {
return _offset;
}
Windows 时间获取基于GetSystemTimeAsFileTime()
,返回一个FILETIME
。这种结构可以追溯到32位系统,由两个32位字段 dwHighDateTime
和组成dwLowDateTime
,它们组合在一起,定义了从新纪元以来的100位纳秒间隔的64位数字(long)
经过资料反馈,Linux封装的方法效率还要低于Windows
-
解决方案 一: https://www.jianshu.com/p/d2039190b1cb
-
解决方案 二: https://www.cnblogs.com/ppgeneve/p/9351788.html
Date的方法
序号 |
方法和描述 |
1 |
boolean after(Date date) 若当调用此方法的Date对象在指定日期之后返回true,否则返回false。 |
2 |
boolean before(Date date) 若当调用此方法的Date对象在指定日期之前返回true,否则返回false。 |
3 |
Object clone( ) 返回此对象的副本。 |
4 |
int compareTo(Date date) 比较当调用此方法的Date对象和指定日期。两者相等时候返回0。调用对象在指定日期之前则返回负数。调用对象在指定日期之后则返回正数。 |
5 |
int compareTo(Object obj) 若obj是Date类型则操作等同于compareTo(Date) 。否则它抛出ClassCastException。 |
6 |
boolean equals(Object date) 当调用此方法的Date对象和指定日期相等时候返回true,否则返回false。 |
7 |
long getTime( ) 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。 |
8 |
int hashCode( ) 返回此对象的哈希码值。 |
9 |
void setTime(long time) 用自1970年1月1日00:00:00 GMT以后time毫秒数设置时间和日期。 |
10 |
String toString( ) 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。 |
Date的格式化编码
时间模式字符串用来指定时间格式。在此模式中,所有的 ASCII 字母被保留为模式字母
定义如下:
字母 |
描述 |
示例 |
G |
纪元标记 |
AD |
y |
四位年份 |
2001 |
M |
月份 |
July or 07 |
d |
一个月的日期 |
10 |
h |
A.M./P.M. (1~12)格式小时 |
12 |
H |
一天中的小时 (0~23) |
22 |
m |
分钟数 |
30 |
s |
秒数 |
55 |
S |
毫秒数 |
234 |
E |
星期几 |
Tuesday |
D |
一年中的日子 |
360 |
F |
一个月中第几周的周几 |
2 (second Wed. in July) |
w |
一年中第几周 |
40 |
W |
一个月中第几周 |
1 |
a |
A.M./P.M. 标记 |
PM |
k |
一天中的小时(1~24) |
24 |
K |
A.M./P.M. (0~11)格式小时 |
10 |
z |
时区 |
Eastern Standard Time |
’ |
文字定界符 |
Delimiter |
" |
单引号 |
` |
使用 SimpleDateFormat 格式化日期
SimpleDateFormat 是一个以语言环境敏感的方式来格式化和分析日期的类。SimpleDateFormat 允许你选择任何用户自定义日期时间格式来运行。
import java.util.*;
import java.text.*;
public class DateDemo {
public static void main(String args[]) {
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
System.out.println("当前时间为: " + ft.format(dNow));
}
}
输出结果
Current Date: Wed 2016.11.09 at 08:23:19 AM UTC
使用printf格式化日期
printf 方法可以很轻松地格式化时间和日期。使用两个字母格式,它以 %t 开头并且以下面表格中的一个字母结尾。
转 换 符 |
说 明 |
示 例 |
c |
包括全部日期和时间信息 |
星期六 十月 27 14:21:20 CST 2007 |
F |
"年-月-日"格式 |
2007-10-27 |
D |
"月/日/年"格式 |
10/27/07 |
r |
"HH:MM:SS PM"格式(12时制) |
02:25:51 下午 |
T |
"HH:MM:SS"格式(24时制) |
14:28:16 |
R |
"HH:MM"格式(24时制) |
14:28 |
实例:
import java.util.Date;
public class DateDemo {
public static void main(String args[]) {
// 初始化 Date 对象
Date date = new Date();
//c的使用
System.out.printf("全部日期和时间信息:%tc%n",date);
//f的使用
System.out.printf("年-月-日格式:%tF%n",date);
//d的使用
System.out.printf("月/日/年格式:%tD%n",date);
//r的使用
System.out.printf("HH:MM:SS PM格式(12时制):%tr%n",date);
//t的使用
System.out.printf("HH:MM:SS格式(24时制):%tT%n",date);
//R的使用
System.out.printf("HH:MM格式(24时制):%tR",date);
}
}
以上实例编译运行结果如下:
全部日期和时间信息:星期一 九月 10 10:43:36 CST 2012
年-月-日格式:2012-09-10
月/日/年格式:09/10/12
HH:MM:SS PM格式(12时制):10:43:36 上午
HH:MM:SS格式(24时制):10:43:36
HH:MM格式(24时制):10:43
更多例子:https://www.runoob.com/java/java-date-time.html