ThinkWon的博客 http://www.gifted-edu.com/ https://csdnimg.cn/release/phoenix/static_blog/images/logo.gif 敏于觀察,勤于思考,善于綜合,勇于創新。 http://www.gifted-edu.com/ThinkWon zh-cn http://www.gifted-edu.com/ 5 2021/01/17 07:03:13 <![CDATA[[原]博客之星,有你的鼓勵更精彩]]> http://www.gifted-edu.com/ThinkWon/article/details/112517796 http://www.gifted-edu.com/ThinkWon/article/details/112517796 ThinkWon 2021/01/12 12:34:39

文章目錄

大家好,我是CSDN的博主ThinkWon,2018年加入CSDN,三年來將工作學習中遇到的包括Java面試總結、并發編程、Java虛擬機與Spring Cloud等方面的知識進

行歸納總結,以分享交流學習的心態,在CSDN共發布了250余篇文章,獲得了超過600萬的訪問量,13萬+的粉絲,得到了大家的積極好評。

2020博客之星年度總評選中成功入圍Top200,希望大家幫我投票,每天都可以投多票哦,點擊鏈接:https://bss.csdn.net/m/topic/blog_star2020/detail?username=thinkwon,然后點擊最大,再點擊投TA一票就可以啦,謝謝各位大牛,您的鼓勵是我創作的最大動力!

在這里插入圖片描述

在技術的世界里,ThinkWon將一路與你相伴!創作出更多更高質量的文章!2020為努力奮斗的你點贊,?新的一年,祝各位大牛牛氣沖天牛年大吉

在這里插入圖片描述

手機用戶可掃下方二維碼進行投票哦!

在這里插入圖片描述

附:CSDN年度報告

在這里插入圖片描述

在這里插入圖片描述

作者:ThinkWon 發表于 2021/01/12 12:34:39 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/112517796
閱讀:1992 評論:6 查看評論
]]>
<![CDATA[[原]PyCharm常用配置和常用插件]]> http://www.gifted-edu.com/ThinkWon/article/details/112412783 http://www.gifted-edu.com/ThinkWon/article/details/112412783 ThinkWon 2021/01/09 22:51:26

常用配置

以下配置能使用File -> New Projects Settings -> Settings for New Projects進行配置的盡量用這個配置,因為這個配置是作用于所有新建項目的,不能用的選擇File -> Settings

在這里插入圖片描述

配置Python解釋器

在這里插入圖片描述

文件編碼

在這里插入圖片描述

文件和代碼模板

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @author JourWon
# @date ${DATE}
# @file ${NAME}.py

在這里插入圖片描述

修改主題

在這里插入圖片描述

修改字體

在這里插入圖片描述

快捷鍵風格

在這里插入圖片描述

顯示行數和方法線

在這里插入圖片描述

代碼自動提示快捷鍵

移除占用Alt+斜杠的快捷鍵

在這里插入圖片描述

設置Basic快捷鍵為Alt+斜杠

在這里插入圖片描述

鼠標懸停顯示文檔說明

在這里插入圖片描述

關閉自動更新

在這里插入圖片描述

安裝 autopep8 工具

PEP8是 Python Enhancement Proposal 8的縮寫,翻譯過來就是 Python增強建議書,也就是Python編碼規范。

Mac安裝方式

命令行輸入pip install autopep8,如果執行autopep8 --version命令,輸出類似autopep8 1.5.4 (pycodestyle: 2.6.0)的信息,則說明安裝成功

Win10安裝方式

在這里插入圖片描述

搜索autopep8,點擊Install Package

在這里插入圖片描述

安裝完成之后左下角會出現Packages autopep8 installed successful等信息

在這里插入圖片描述

  • Name:autopep8(可以隨便取)
  • Tools settings
    • ProgramsC:\dev\anaconda3\Lib\site-packages\autopep8.py
    • Parameters--in-place --aggressive --aggressive $FilePath$
    • Working directory$ProjectFileDir$

Output Filters設置:

  • regular expression to match output$FILE_PATH$:$LINE$:$COLUMN$:.*

autopep8在pycharm中的使用:在Pycharm編輯其中新建一個python文件,編輯一些不符合pep8風格的代碼;將鼠標放在該文件的編輯器中→右鍵→External Tools→點擊Autopep8。這樣你的代碼就符合pep8的風格了。

在這里插入圖片描述

啟動不打開上一個項目

在這里插入圖片描述

導出導入配置

導出配置

file -> Manage IDE Settings -> export setting,設置導出的settings.jar包的位置,然后點擊OK

在這里插入圖片描述

導入配置

file -> Manage IDE Settings -> import settings,選擇你想要導入的 settings.jar即可

常用插件

  • Translation -翻譯插件

  • CodeGlance -代碼地圖

  • .ignore -git忽略文件

  • Key Promoter X -一款可以進行快捷鍵提示的插件

  • AceJump -一款可以徹底擺脫鼠標的插件

  • String Manipulation -一款強大的字符串轉換工具

  • GsonFormat -將JSON字符串轉換為內部類實體類插件

  • ideaVim -讓我們在 Pycharm 中 使用 vim 來編輯代碼

  • Markdown -md文件編輯查看

  • Regex Tester -PyCharm的第三方插件,可以測試正則表達式

  • Json Parser -json格式化工具

  • Statistic -statistic項目統計插件,統計整體代碼量,包括所有文件的統計數量和行數

  • Rainbow Brackets -彩虹顏色的括號,清除分清括號個數,防止括號錯亂

作者:ThinkWon 發表于 2021/01/09 22:51:26 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/112412783
閱讀:688 評論:11 查看評論
]]>
<![CDATA[[原]PyCharm2020.3.2安裝]]> http://www.gifted-edu.com/ThinkWon/article/details/112412497 http://www.gifted-edu.com/ThinkWon/article/details/112412497 ThinkWon 2021/01/09 22:45:55

PyCharm是目前 Python 語言最好用的集成開發工具,可以幫助用戶提高開發效率。

1.下載 Pycharm

在 Pycharm 的官網即可下載,鏈接如下

PyCharm for Windows :https://www.jetbrains.com/pycharm/download/#section=windows

PyCharm for Mac :https://www.jetbrains.com/pycharm/download/#section=mac

PyCharm for Linux :https://www.jetbrains.com/pycharm/download/#section=linux

版本選擇

下載時有兩種版本選擇 Professional(專業版,收費)和Community(社區版,免費)

一般來說,我們使用Community版本就夠了,除非你需要用 Python 進行 Django 等 Web 開發時才需要用到專業版。

在這里插入圖片描述

2.安裝 Pycharm

第一步,雙擊 exe 文件,直接點擊 Next

在這里插入圖片描述

第二步,如果要修改安裝路徑,就在這里更改:

在這里插入圖片描述

第三步,需要進行一些設置,如果你無特殊需要按照圖中勾選即可:

在這里插入圖片描述

如果有特殊需要,請按如下描述確定是否勾選設置:

  1. 創建快捷方式:默認根據你當前系統進行選擇;
  2. 將 pycharm 的啟動目錄添加到環境變量(需要重啟),如果需要使用命令行操作 pycharm,則勾選該選項;
  3. 添加鼠標右鍵菜單,使用打開項目的方式打開文件夾。如果你經常需要下載一些別人的代碼查看,可以勾選此選項,這會增加鼠標右鍵菜單的選項;
  4. 將所有 py 文件關聯到 pycharm,也就是你雙擊你電腦上的 py 文件,會默認使用 pycharm 打開。不建議勾選,pycharm 每次打開的速度會比較慢。你要單獨打開 py 文件,建議使用 notepad++ 等文本編輯器,打開速度會更快;

第四步,默認即可,點擊 install

在這里插入圖片描述

第五步,耐心的等待兩分鐘左右,之后就會得到下面的安裝完成的界面,勾選Run Pycharm,點擊Finish,PyCharm2020.3.2安裝完成。

在這里插入圖片描述

3.配置 Pycharm

首次啟動 pycharm,會彈出配置窗口,如果你之前使用過 pycharm 并有相關的配置文件,則在此處選擇;如果沒有,默認即可。

在這里插入圖片描述

選擇30天免費試用,點擊Evaluate for free,然后點擊Evaluate

在這里插入圖片描述

配置完成,界面如下

在這里插入圖片描述

4.創建項目

創建 Python 項目

這里選擇New Project

在這里插入圖片描述

設置項目名稱和選擇解釋器

如果出現 No Python interpreter selected 表示 Python 的環境變量有問題。這里我們使用自己的解釋器

注意:這里默認使用的 Python 的虛擬環境,如果你不使用虛擬環境,一定要修改。

在這里插入圖片描述

選擇系統解釋器,找到你安裝的 Python 目錄,點擊OK

在這里插入圖片描述

然后點擊 Create 即可

在這里插入圖片描述

那么現在項目就創建成功了,去掉 Show tips on startup,不用每次都打開歡迎界面,然后關閉即可。

在這里插入圖片描述

5.測試運行 Python 文件

剛才我們創建項目的時候,默認勾選了Create a main.py welcome scriptPyCharm默認會幫我們創建main.py文件,鍵盤輸入Shift+F10,即可運行

在這里插入圖片描述

輸出結果

在這里插入圖片描述

作者:ThinkWon 發表于 2021/01/09 22:45:55 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/112412497
閱讀:692 評論:2 查看評論
]]>
<![CDATA[[原]Anaconda安裝]]> http://www.gifted-edu.com/ThinkWon/article/details/112412165 http://www.gifted-edu.com/ThinkWon/article/details/112412165 ThinkWon 2021/01/09 22:40:52

1.Anaconda是什么

Anaconda指的是一個開源的Python發行版本,其包含了conda、Python等180多個科學包及其依賴項。Anaconda也是Python的包管理器和環境管理器。

先來解決一個初學者都會問的問題:我已經安裝了Python,那么為什么還需要Anaconda呢?原因有以下幾點:

(1)Anaconda附帶了一大批常用數據科學包,它附帶了conda、Python和 180 多個科學包及其依賴項。因此你可以用Anaconda立即開始處理數據。

(2)管理包。Anaconda 是在 conda(一個包管理器和環境管理器)上發展出來的。在數據分析中,你會用到很多第三方的包,而conda(包管理器)可以很好的幫助你在計算機上安裝和管理這些包,包括安裝、卸載和更新包。

(3)管理環境。為什么需要管理環境呢?比如你在A項目中用到了Python2,而新的項目要求使用Python3,而同時安裝兩個Python版本可能會造成許多混亂和錯誤。這時候conda就可以幫助你為不同的項目建立不同的運行環境。還有很多項目使用的包版本不同,比如不同的pandas版本,不可能同時安裝兩個pandas版本。你要做的應該是在項目對應的環境中創建對應的pandas版本。這時候conda就可以幫你做到。

總結:Anaconda解決了官方Python的兩大痛點:

(1)提供了包管理功能,Windows平臺安裝第三方包經常失敗的場景得以解決。

(2)提供環境管理功能,解決了多版本Python并存、切換的問題。

2.Anaconda下載

在這里插入圖片描述

3.Anaconda安裝

打開下載好的 Anaconda 文件,出現如下界面,點擊Next即可

在這里插入圖片描述

用戶協議,點擊I Agree

在這里插入圖片描述

Just Me,然后點擊Next

在這里插入圖片描述

選擇安裝路徑

注意:路徑要簡單,不要有空格!!!不要有中文字符!!!

在這里插入圖片描述

接下來是重中之重,第一個選項是添加環境變量,默認是沒有勾選的,請務必勾選上,如果這里不勾選,后續安裝完成后想要自行添加環境變量會比較麻煩。

勾選完后點擊 Install 安裝。

在這里插入圖片描述

安裝完成,點擊Next

在這里插入圖片描述

這里是Pycharm的一個推廣,沒有需求的話可以不用管,最后一步了,繼續點Next

在這里插入圖片描述

進入Thanks for installing Anaconda!界面則意味著安裝成功,點擊Finish完成安裝。

在這里插入圖片描述

4.Anaconda環境變量配置

如果安裝Anaconda時勾選了Add Anaconda3 to my PATH environment variable,可以忽略此步驟,如果沒有勾選則需要進行配置

此電腦—屬性—高級系統設置—環境變量—path—編輯—新建,路徑根據自己的安裝路徑進行修改

C:\dev\anaconda3

C:\dev\anaconda3\Library\mingw-w64\bin

C:\dev\anaconda3\Library\usr\bin

C:\dev\anaconda3\Library\bin

C:\dev\anaconda3\Scripts

在這里插入圖片描述

5.檢驗是否安裝成功

在cmd中輸入:python,查看是否有Python環境?

在這里插入圖片描述

在cmd中輸入:conda --version,查看是否有conda環境? (檢驗安裝成功的標志)

在這里插入圖片描述

在cmd中輸入: conda info (檢驗安裝成功的標志)

在這里插入圖片描述

更新所有包

初次安裝的包一般比較老,為了避免之后使用報錯,可以輸入conda update --all命令,把所有包進行更新。

在這里插入圖片描述

在提示是否更新的時候輸入 y(Yes)讓更新繼續。

6.檢驗Anaconda Navifator是否安裝成功

點擊Anaconda Navifator,看是否能夠進入界面,若成功,大功告成。

在這里插入圖片描述

點擊Anaconda Navigator(anaconda3),界面如下說明安裝成功

在這里插入圖片描述

7.修改Anaconda鏡像

為了加快包下載速度,國內一般使用清華大學鏡像,鏈接地址:清華大學開源軟件鏡像站

Anaconda | 鏡像站使用幫助 | 清華大學開源軟件鏡像站 | Tsinghua Open Source Mirror

注:由于更新過快難以同步,清華大學鏡像不同步pytorch-nightly, pytorch-nightly-cpu, ignite-nightly這三個包。

修改為清華大學鏡像

直接打開cmd輸入以下命令

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/

conda config --set show_channel_urls yes

即可添加 Anaconda Python 免費倉庫。

運行 conda clean -i 清除索引緩存,保證用的是鏡像站提供的索引。

在cmd中輸入: conda info,結果如下說明配置鏡像成功

在這里插入圖片描述

移除清華大學鏡像

如果需要移除鏡像,直接打開cmd輸入以下命令

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/

8.PyCharm配置Anaconda

方式一(建立新的項目時)

1、點擊創建新項目

在這里插入圖片描述

2、如圖所示進行選擇,如果紅框內的python程序不是你anaconda安裝位置的python,點擊右邊“…”進行選擇

在這里插入圖片描述

方式二(已經打開項目)

1、點擊File -> Settings,進入項目設置

在這里插入圖片描述

2、進入項目設置里的Project Interpreter,如果紅框內的python程序不是你anaconda安裝位置的python,點擊設置,點擊Add選項

在這里插入圖片描述

4、選擇自己Anaconda下的python程序

在這里插入圖片描述

5、點擊apply,完成應用

在這里插入圖片描述

9.總結

Anaconda是一款強大的軟件也是python程序員必備的軟件,盡量達到每個項目單獨一個虛擬環境,因為后面使用pyinstaller打包的項目成為可執行文件的時候,會打包環境里所有安裝的包,該環境下每個包都是我們項目用到才安裝的,非常干凈,這樣會加快文件的運行速度也減小文件的大小,便于我們管理和維護!

作者:ThinkWon 發表于 2021/01/09 22:40:52 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/112412165
閱讀:261 評論:1 查看評論
]]>
<![CDATA[[原]Win10安裝Python3.9]]> http://www.gifted-edu.com/ThinkWon/article/details/112411897 http://www.gifted-edu.com/ThinkWon/article/details/112411897 ThinkWon 2021/01/09 22:34:52

1.下載Python3.9.1

Python 安裝包下載地址:https://www.python.org/downloads/

打開該鏈接,點擊下圖中的版本號或者Download按鈕進入對應版本的下載頁面,滾動到最后即可看到各個平臺的 Python 安裝包。

在這里插入圖片描述

這里點擊安裝最新版的Python 3.9.1

在這里插入圖片描述

對前綴的說明:

  • Windows installer (64-bit)開頭的是 64 位的 Python 安裝程序;

  • Windows installer (32-bit)開頭的是 32 位的 Python 安裝程序。

對后綴的說明:

  • embeddable zip file表示.zip格式的綠色免安裝版本,可以直接嵌入(集成)到其它的應用程序中;
  • executable installer表示.exe格式的可執行程序,這是完整的離線安裝包,一般選擇這個即可;
  • web-based installer表示通過網絡安裝的,也就是說下載到的是一個空殼,安裝過程中還需要聯網下載真正的 Python 安裝包。

這里我選擇的是Windows installer (64-bit),也即 64 位的完整的離線安裝包。

2.安裝Python3.9.1

Python 安裝向導

雙擊下載得到的 python-3.9.1-amd64.exe,就可以正式開始安裝 Python 了

在這里插入圖片描述

勾選Add Python 3.9 to PATH,這樣可以將 Python 命令工具所在目錄添加到系統 Path 環境變量中,以后開發程序或者運行 Python 命令會非常方便。

Python 支持兩種安裝方式,默認安裝和自定義安裝:

  • 默認安裝會勾選所有組件,并安裝在 C 盤;
  • 自定義安裝可以手動選擇要安裝的組件,并安裝到指定盤符。

這里我們選擇自定義安裝。點擊Customize installation進行入下一步

選擇要安裝的 Python 組件

在這里插入圖片描述

  • Documentation 離線的 .chm 格式文檔,必須保留。英文還 OK 的小伙伴可以直接看這份文檔,比所有書都靠譜。看英文有壓力的,平時隨時查查標準庫模塊用法什么的是極好的。
  • pip Python 包下載工具,必須保留。
  • tcl/tk and IDLE ,說來話長,保留就對了。
  • Python test suite,這個可以沒有,當然留下來也沒關系。
  • py launcher。這里額外注意的是 for all user 選項,可以選擇是否對所有用戶安裝。如果對所有用戶安裝,則需要 administrator 的權限。

沒有特殊要求的話,保持默認即可,也就是全部勾選。

選擇安裝目錄

點擊Next繼續,選擇安裝目錄。

在這里插入圖片描述

  • Install for all user,是否對所有人安裝,如果是,需要 administrator 的權限,并且安裝路徑會有所不同。
  • 關聯文件到 Python,這個保持原樣即可。它就是把 .py 文件和 python 程序關聯起來,這樣雙擊 .py 文件的時候,自動就用 python 去執行了。
  • 創建快捷方式,保持原樣即可。
  • 添加 Python 到環境變量,第 2 次修改的機會
  • 預編譯標準庫,一次性的把標準庫的 .py 都預編譯成 .pyc,沒什么必要,會多花費安裝時間,不選
  • 兩個 download debug xxx ,不知道哪里會用到,都不選

注意:安裝路徑文件夾名稱均不能含有中文字符

選擇好你常用的安裝目錄,點擊Install,等待幾分鐘。

禁用系統的Path長度自動限制

安裝成功后結束界面可能會出現Disable path length limit的按鈕,有的話點一下就好了,作用是禁用系統的Path長度自動限制,能給我們避免很多的麻煩。

在這里插入圖片描述

點擊Close,至此,python安裝完成

在這里插入圖片描述

3.驗證安裝成功

安裝完成以后,打開 Windows 的命令行程序(命令提示符),同時按下Windows+R輸入cmd,進入dos窗口

在這里插入圖片描述

在窗口中輸入python命令(注意字母p是小寫的),如果出現 Python 的版本信息,并看到命令提示符>>>,就說明安裝成功了。

運行 Python 命令

在這里插入圖片描述

運行 python 命令啟動的是 python 交互式編程環境,我們可以在>>>后面輸入代碼,并立即看到執行結果。

在 Python 交互式環境中編寫代碼

在這里插入圖片描述

按下Ctrl+Z快捷鍵,或者輸入exit()命令即可退出交互式編程環境,回到 Windows 命令行程序。

作者:ThinkWon 發表于 2021/01/09 22:34:52 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/112411897
閱讀:249
]]>
<![CDATA[[原]史上最全Java8日期時間工具類]]> http://www.gifted-edu.com/ThinkWon/article/details/111116600 http://www.gifted-edu.com/ThinkWon/article/details/111116600 ThinkWon 2020/12/13 14:52:18

文章目錄

這是我總結的Java8日期工具類,應該是比較全面的,滿足日常開發絕大部分需求,分享給大家,有錯誤之處,還望大神指教。

/**
 * Java8日期時間工具類
 *
 * @author JourWon
 * @date 2020/12/13
 */
public class LocalDateUtils {

    /**
     * 顯示年月日時分秒,例如 2015-08-11 09:51:53.
     */
    public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 僅顯示年月日,例如 2015-08-11.
     */
    public static final String DATE_PATTERN = "yyyy-MM-dd";

    /**
     * 僅顯示時分秒,例如 09:51:53.
     */
    public static final String TIME_PATTERN = "HH:mm:ss";

    /**
     * 顯示年月日時分秒(無符號),例如 20150811095153.
     */
    public static final String UNSIGNED_DATETIME_PATTERN = "yyyyMMddHHmmss";

    /**
     * 僅顯示年月日(無符號),例如 20150811.
     */
    public static final String UNSIGNED_DATE_PATTERN = "yyyyMMdd";

    /**
     * 春天;
     */
    public static final Integer SPRING = 1;

    /**
     * 夏天;
     */
    public static final Integer SUMMER = 2;

    /**
     * 秋天;
     */
    public static final Integer AUTUMN = 3;

    /**
     * 冬天;
     */
    public static final Integer WINTER = 4;

    /**
     * 星期日;
     */
    public static final String SUNDAY = "星期日";

    /**
     * 星期一;
     */
    public static final String MONDAY = "星期一";

    /**
     * 星期二;
     */
    public static final String TUESDAY = "星期二";

    /**
     * 星期三;
     */
    public static final String WEDNESDAY = "星期三";

    /**
     * 星期四;
     */
    public static final String THURSDAY = "星期四";

    /**
     * 星期五;
     */
    public static final String FRIDAY = "星期五";

    /**
     * 星期六;
     */
    public static final String SATURDAY = "星期六";

    /**
     * 年
     */
    private static final String YEAR = "year";

    /**
     * 月
     */
    private static final String MONTH = "month";

    /**
     * 周
     */
    private static final String WEEK = "week";

    /**
     * 日
     */
    private static final String DAY = "day";

    /**
     * 時
     */
    private static final String HOUR = "hour";

    /**
     * 分
     */
    private static final String MINUTE = "minute";

    /**
     * 秒
     */
    private static final String SECOND = "second";

    /**
     * 獲取當前日期和時間字符串.
     *
     * @return String 日期時間字符串,例如 2015-08-11 09:51:53
     */
    public static String getLocalDateTimeStr() {
        return format(LocalDateTime.now(), DATETIME_PATTERN);
    }

    /**
     * 獲取當前日期字符串.
     *
     * @return String 日期字符串,例如2015-08-11
     */
    public static String getLocalDateStr() {
        return format(LocalDate.now(), DATE_PATTERN);
    }

    /**
     * 獲取當前時間字符串.
     *
     * @return String 時間字符串,例如 09:51:53
     */
    public static String getLocalTimeStr() {
        return format(LocalTime.now(), TIME_PATTERN);
    }

    /**
     * 獲取當前星期字符串.
     *
     * @return String 當前星期字符串,例如 星期二
     */
    public static String getDayOfWeekStr() {
        return format(LocalDate.now(), "E");
    }

    /**
     * 獲取指定日期是星期幾
     *
     * @param localDate 日期
     * @return String 星期幾
     */
    public static String getDayOfWeekStr(LocalDate localDate) {
        String[] weekOfDays = {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};
        int dayOfWeek = localDate.getDayOfWeek().getValue() - 1;
        return weekOfDays[dayOfWeek];
    }

    /**
     * 獲取日期時間字符串
     *
     * @param temporal 需要轉化的日期時間
     * @param pattern  時間格式
     * @return String 日期時間字符串,例如 2015-08-11 09:51:53
     */
    public static String format(TemporalAccessor temporal, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return dateTimeFormatter.format(temporal);
    }

    /**
     * 日期時間字符串轉換為日期時間(java.time.LocalDateTime)
     *
     * @param localDateTimeStr 日期時間字符串
     * @param pattern          日期時間格式 例如DATETIME_PATTERN
     * @return LocalDateTime 日期時間
     */
    public static LocalDateTime parseLocalDateTime(String localDateTimeStr, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(localDateTimeStr, dateTimeFormatter);
    }

    /**
     * 日期字符串轉換為日期(java.time.LocalDate)
     *
     * @param localDateStr 日期字符串
     * @param pattern      日期格式 例如DATE_PATTERN
     * @return LocalDate 日期
     */
    public static LocalDate parseLocalDate(String localDateStr, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDate.parse(localDateStr, dateTimeFormatter);
    }

    /**
     * 獲取指定日期時間加上指定數量日期時間單位之后的日期時間.
     *
     * @param localDateTime 日期時間
     * @param num           數量
     * @param chronoUnit    日期時間單位
     * @return LocalDateTime 新的日期時間
     */
    public static LocalDateTime plus(LocalDateTime localDateTime, int num, ChronoUnit chronoUnit) {
        return localDateTime.plus(num, chronoUnit);
    }

    /**
     * 獲取指定日期時間減去指定數量日期時間單位之后的日期時間.
     *
     * @param localDateTime 日期時間
     * @param num           數量
     * @param chronoUnit    日期時間單位
     * @return LocalDateTime 新的日期時間
     */
    public static LocalDateTime minus(LocalDateTime localDateTime, int num, ChronoUnit chronoUnit) {
        return localDateTime.minus(num, chronoUnit);
    }

    /**
     * 根據ChronoUnit計算兩個日期時間之間相隔日期時間
     *
     * @param start      開始日期時間
     * @param end        結束日期時間
     * @param chronoUnit 日期時間單位
     * @return long 相隔日期時間
     */
    public static long getChronoUnitBetween(LocalDateTime start, LocalDateTime end, ChronoUnit chronoUnit) {
        return Math.abs(start.until(end, chronoUnit));
    }

    /**
     * 根據ChronoUnit計算兩個日期之間相隔年數或月數或天數
     *
     * @param start      開始日期
     * @param end        結束日期
     * @param chronoUnit 日期時間單位,(ChronoUnit.YEARS,ChronoUnit.MONTHS,ChronoUnit.WEEKS,ChronoUnit.DAYS)
     * @return long 相隔年數或月數或天數
     */
    public static long getChronoUnitBetween(LocalDate start, LocalDate end, ChronoUnit chronoUnit) {
        return Math.abs(start.until(end, chronoUnit));
    }

    /**
     * 獲取本年第一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getFirstDayOfYearStr() {
        return getFirstDayOfYearStr(LocalDateTime.now());
    }

    /**
     * 獲取本年最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfYearStr() {
        return getLastDayOfYearStr(LocalDateTime.now());
    }

    /**
     * 獲取指定日期當年第一天的日期字符串
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getFirstDayOfYearStr(LocalDateTime localDateTime) {
        return getFirstDayOfYearStr(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 獲取指定日期當年最后一天的日期字符串
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfYearStr(LocalDateTime localDateTime) {
        return getLastDayOfYearStr(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 獲取指定日期當年第一天的日期字符串,帶日期格式化參數
     *
     * @param localDateTime 指定日期時間
     * @param pattern       日期時間格式
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getFirstDayOfYearStr(LocalDateTime localDateTime, String pattern) {
        return format(localDateTime.withDayOfYear(1).withHour(0).withMinute(0).withSecond(0), pattern);
    }

    /**
     * 獲取指定日期當年最后一天的日期字符串,帶日期格式化參數
     *
     * @param localDateTime 指定日期時間
     * @param pattern       日期時間格式
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfYearStr(LocalDateTime localDateTime, String pattern) {
        return format(localDateTime.with(TemporalAdjusters.lastDayOfYear()).withHour(23).withMinute(59).withSecond(59), pattern);
    }

    /**
     * 獲取本月第一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getFirstDayOfMonthStr() {
        return getFirstDayOfMonthStr(LocalDateTime.now());
    }

    /**
     * 獲取本月最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfMonthStr() {
        return getLastDayOfMonthStr(LocalDateTime.now());
    }

    /**
     * 獲取指定日期當月第一天的日期字符串
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getFirstDayOfMonthStr(LocalDateTime localDateTime) {
        return getFirstDayOfMonthStr(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 獲取指定日期當月最后一天的日期字符串
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfMonthStr(LocalDateTime localDateTime) {
        return getLastDayOfMonthStr(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 獲取指定日期當月第一天的日期字符串,帶日期格式化參數
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getFirstDayOfMonthStr(LocalDateTime localDateTime, String pattern) {
        return format(localDateTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0), pattern);
    }

    /**
     * 獲取指定日期當月最后一天的日期字符串,帶日期格式化參數
     *
     * @param localDateTime 指定日期時間
     * @param pattern       日期時間格式
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfMonthStr(LocalDateTime localDateTime, String pattern) {
        return format(localDateTime.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59), pattern);
    }

    /**
     * 獲取本周第一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getFirstDayOfWeekStr() {
        return getFirstDayOfWeekStr(LocalDateTime.now());
    }

    /**
     * 獲取本周最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfWeekStr() {
        return getLastDayOfWeekStr(LocalDateTime.now());
    }

    /**
     * 獲取指定日期當周第一天的日期字符串,這里第一天為周一
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getFirstDayOfWeekStr(LocalDateTime localDateTime) {
        return getFirstDayOfWeekStr(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 獲取指定日期當周最后一天的日期字符串,這里最后一天為周日
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfWeekStr(LocalDateTime localDateTime) {
        return getLastDayOfWeekStr(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 獲取指定日期當周第一天的日期字符串,這里第一天為周一,帶日期格式化參數
     *
     * @param localDateTime 指定日期時間
     * @param pattern       日期時間格式
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getFirstDayOfWeekStr(LocalDateTime localDateTime, String pattern) {
        return format(localDateTime.with(DayOfWeek.MONDAY).withHour(0).withMinute(0).withSecond(0), pattern);
    }

    /**
     * 獲取指定日期當周最后一天的日期字符串,這里最后一天為周日,帶日期格式化參數
     *
     * @param localDateTime 指定日期時間
     * @param pattern       日期時間格式
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getLastDayOfWeekStr(LocalDateTime localDateTime, String pattern) {
        return format(localDateTime.with(DayOfWeek.SUNDAY).withHour(23).withMinute(59).withSecond(59), pattern);
    }

    /**
     * 獲取今天開始時間的日期字符串
     *
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getStartTimeOfDayStr() {
        return getStartTimeOfDayStr(LocalDateTime.now());
    }

    /**
     * 獲取今天結束時間的日期字符串
     *
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getEndTimeOfDayStr() {
        return getEndTimeOfDayStr(LocalDateTime.now());
    }

    /**
     * 獲取指定日期開始時間的日期字符串
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 00:00:00
     */
    public static String getStartTimeOfDayStr(LocalDateTime localDateTime) {
        return getStartTimeOfDayStr(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 獲取指定日期結束時間的日期字符串
     *
     * @param localDateTime 指定日期時間
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getEndTimeOfDayStr(LocalDateTime localDateTime) {
        return getEndTimeOfDayStr(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 獲取指定日期開始時間的日期字符串,帶日期格式化參數
     *
     * @param localDateTime 指定日期時間
     * @param pattern       日期時間格式
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getStartTimeOfDayStr(LocalDateTime localDateTime, String pattern) {
        return format(localDateTime.withHour(0).withMinute(0).withSecond(0), pattern);
    }

    /**
     * 獲取指定日期結束時間的日期字符串,帶日期格式化參數
     *
     * @param localDateTime 指定日期時間
     * @param pattern       日期時間格式
     * @return String 格式:yyyy-MM-dd 23:59:59
     */
    public static String getEndTimeOfDayStr(LocalDateTime localDateTime, String pattern) {
        return format(localDateTime.withHour(23).withMinute(59).withSecond(59), pattern);
    }

    /**
     * 切割日期。按照周期切割成小段日期段。例如: <br>
     *
     * @param startDate 開始日期(yyyy-MM-dd)
     * @param endDate   結束日期(yyyy-MM-dd)
     * @param period    周期(天,周,月,年)
     * @return 切割之后的日期集合
     * <li>startDate="2019-02-28",endDate="2019-03-05",period="day"</li>
     * <li>結果為:[2019-02-28, 2019-03-01, 2019-03-02, 2019-03-03, 2019-03-04, 2019-03-05]</li><br>
     * <li>startDate="2019-02-28",endDate="2019-03-25",period="week"</li>
     * <li>結果為:[2019-02-28,2019-03-06, 2019-03-07,2019-03-13, 2019-03-14,2019-03-20,
     * 2019-03-21,2019-03-25]</li><br>
     * <li>startDate="2019-02-28",endDate="2019-05-25",period="month"</li>
     * <li>結果為:[2019-02-28,2019-02-28, 2019-03-01,2019-03-31, 2019-04-01,2019-04-30,
     * 2019-05-01,2019-05-25]</li><br>
     * <li>startDate="2019-02-28",endDate="2020-05-25",period="year"</li>
     * <li>結果為:[2019-02-28,2019-12-31, 2020-01-01,2020-05-25]</li><br>
     */
    public static List<String> listDateStrs(String startDate, String endDate, String period) {
        List<String> result = new ArrayList<>();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
        LocalDate end = LocalDate.parse(endDate, dateTimeFormatter);
        LocalDate start = LocalDate.parse(startDate, dateTimeFormatter);
        LocalDate tmp = start;
        switch (period) {
            case DAY:
                while (start.isBefore(end) || start.isEqual(end)) {
                    result.add(start.toString());
                    start = start.plusDays(1);
                }
                break;
            case WEEK:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    if (tmp.plusDays(6).isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + tmp.plusDays(6));
                    }
                    tmp = tmp.plusDays(7);
                }
                break;
            case MONTH:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    LocalDate lastDayOfMonth = tmp.with(TemporalAdjusters.lastDayOfMonth());
                    if (lastDayOfMonth.isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + lastDayOfMonth);
                    }
                    tmp = lastDayOfMonth.plusDays(1);
                }
                break;
            case YEAR:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    LocalDate lastDayOfYear = tmp.with(TemporalAdjusters.lastDayOfYear());
                    if (lastDayOfYear.isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + lastDayOfYear);
                    }
                    tmp = lastDayOfYear.plusDays(1);
                }
                break;
            default:
                break;
        }
        return result;
    }

    public static void main(String[] args) {
        System.out.println(getLocalDateTimeStr());
        System.out.println(getLocalDateStr());
        System.out.println(getLocalTimeStr());
        System.out.println(getDayOfWeekStr());
        System.out.println(getDayOfWeekStr(LocalDate.now()));

        System.out.println("========");
        System.out.println(format(LocalDate.now(), UNSIGNED_DATE_PATTERN));

        System.out.println("========");
        System.out.println(parseLocalDateTime("2020-12-13 11:14:12", DATETIME_PATTERN));
        System.out.println(parseLocalDate("2020-12-13", DATE_PATTERN));

        System.out.println("========");
        System.out.println(plus(LocalDateTime.now(), 3, ChronoUnit.HOURS));
        System.out.println(minus(LocalDateTime.now(), 4, ChronoUnit.DAYS));

        System.out.println("========");
        System.out.println(getChronoUnitBetween(LocalDateTime.now(), parseLocalDateTime("2020-12-12 12:03:12", DATETIME_PATTERN), ChronoUnit.MINUTES));
        System.out.println(getChronoUnitBetween(LocalDate.now(), parseLocalDate("2021-12-12", DATE_PATTERN), ChronoUnit.WEEKS));

        System.out.println("========");
        System.out.println(getFirstDayOfYearStr());
        System.out.println(getFirstDayOfYearStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
        System.out.println(getFirstDayOfYearStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));

        System.out.println(getLastDayOfYearStr());
        System.out.println(getLastDayOfYearStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
        System.out.println(getLastDayOfYearStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));

        System.out.println("========");
        System.out.println(getFirstDayOfMonthStr());
        System.out.println(getFirstDayOfMonthStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
        System.out.println(getFirstDayOfMonthStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));

        System.out.println(getLastDayOfMonthStr());
        System.out.println(getLastDayOfMonthStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
        System.out.println(getLastDayOfMonthStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));

        System.out.println("========");
        System.out.println(getFirstDayOfWeekStr());
        System.out.println(getFirstDayOfWeekStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
        System.out.println(getFirstDayOfWeekStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));

        System.out.println(getLastDayOfWeekStr());
        System.out.println(getLastDayOfWeekStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
        System.out.println(getLastDayOfWeekStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));

        System.out.println("========");
        System.out.println(getStartTimeOfDayStr());
        System.out.println(getStartTimeOfDayStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
        System.out.println(getStartTimeOfDayStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));

        System.out.println(getEndTimeOfDayStr());
        System.out.println(getEndTimeOfDayStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
        System.out.println(getEndTimeOfDayStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));

        System.out.println("========");
        List<String> dateStrs = listDateStrs("2019-01-30", "2020-12-13", YEAR);
        for (String dateStr : dateStrs) {
            System.out.println(dateStr);
        }

        System.out.println("========");
        List<String> dateStrs1 = listDateStrs("2019-01-30", "2020-12-13", MONTH);
        for (String dateStr : dateStrs1) {
            System.out.println(dateStr);
        }

        System.out.println("========");
        List<String> dateStrs2 = listDateStrs("2020-12-01", "2020-12-13", DAY);
        for (String dateStr : dateStrs2) {
            System.out.println(dateStr);
        }
    }

}
作者:ThinkWon 發表于 2020/12/13 14:52:18 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/111116600
閱讀:12198 評論:48 查看評論
]]>
<![CDATA[[原]Java8日期時間API]]> http://www.gifted-edu.com/ThinkWon/article/details/111087199 http://www.gifted-edu.com/ThinkWon/article/details/111087199 ThinkWon 2020/12/12 23:56:51

Java 8以前日期時間API存在的問題

作為開發者,經常需要處理日期時間。在Java 8以前,相信你對 java.util.Datejava.util.Calendarjava.util.GregoiranCalendarjava.text.SimpleDateFormat 這四大類非常熟悉,它們分別用于處理日期、日歷、公歷、日期時間格式化。

這四個類有好多陷阱和坑,比如

  1. 非線程安全:這四大類都不是線程安全的。開發者在使用這些類時必須自己處理多線程并發問題。
  2. 設計不佳 :一方面日期和日期格式化分布在多個包中;另一方面,java.util.Date 的默認日期為1970年1月1日,沒有統一性。而且 Date 類也缺少直接操作日期的相關方法。
  3. 時區處理困難:因為設計不佳,開發人員不得不編寫大量代碼來處理時區問題。
  4. 還有其它一些問題,如Calendar類月份從零開始計算等。

面對種種問題,Java 8 終于重新設計了所有日期時間、日歷及時區相關的 API。并把它們都統一放置在 java.time 包和子包下。并作出了以下改進

  1. 新的日期時間 API 是線程安全的。不僅沒有 setter 方法,而且任何對實例的變更都會返回一個新的實例,保證原來的實例不變。
  2. 新的日期時間 API 提供了大量的方法,用于修改日期時間的各個部分,并返回一個新的實例。
  3. 借鑒了第三方日期時間庫joda很多的優點。
  4. 在時區方面,新的日期時間 API 引入了 ( domain ) 這個概念。

同時 Java 8 還針對原來復雜的 API 進行重新組合和拆分,分成了好多個類。

關于時間和時區

GMT和UTC

GMT,即格林尼治標準時間,也就是世界時。GMT的正午是指當太陽橫穿格林尼治子午線(本初子午線)時的時間。但由于地球自轉不均勻不規則,導致GMT不精確,現在已經不再作為世界標準時間使用。

UTC,即協調世界時。是經過平均太陽時(以格林威治時間 GMT 為準)、地軸運動修正后的新時標,以「秒」為單位的國際原子時所綜合精算而成的時間。為確保UTC與GMT相差不會超過0.9秒,在有需要的情況下(例如 1998-12-31T23:59:60Z)會在UTC內加上正或負閏秒。協調世界時區會使用 “Z” 來表示,協調世界時也會被稱為 “Zulu time”。UTC現在作為世界標準時間使用。

所以,UTC與GMT基本上等同,誤差不超過0.9秒。不過日常使用中,GMT 與 UTC 的功能與精確度是沒有差別的。

時區

時區作為地理概念,表示 “遵守統一時間標準的一個地區”。

使用與 UTC 的偏移來表示時區,例如:中國所在時區為 UTC+08:00(又稱為 Chinese Standard Time,即 “中國標準時間”)

地球自西向東旋轉,東邊比西邊先看到太陽,東邊的時間也比西邊的早。為了統一世界的時間,1884年的國際經度會議規規定將全球劃分為24個時區(東、西各12個時區)。規定英國(格林尼治天文臺舊址)為零時區(基準 UTC),東1-12區,西1-12區,中國北京處于東8區(UTC+08:00),那么我們的時間會領先基準-也就是我們在早上 9 點時,倫敦是早上 1 點。

Unix時間戳

計算機中的Unix時間戳,使用自 1970-01-01T00:00:00Z(Z 即表示 UTC 時間)至今的毫秒差作為表示時間的數值,并且移除期間的“閏秒”(例如 1998-12-31T23:59:60Z),這么做當然是為了簡化計算機對時間操作的復雜度。Unix 時間體系中,每天固定 86400 秒,這個時間是絕對公立的,它和時區沒有任何關系。

Java 中的 Unix 時間

Java 確保:每天 24 小時、每小時 60 分、每分鐘 60 秒。

Java 中獲取 “當前” 時間的方法,其底層實現,全部由 java.lang.System.currentTimeMillis() 提供自 UTC 1970-01-01T00:00:00 的毫秒數。java.lang.System.currentTimeMillis() 作為 native 方法,其實現與 JVM 所在的機器相關(通常使用 NTP 協議保持更新)。

LocalDate、LocalTime、LocalDateTime

java.time.LocalDate 用于表示 “本地日期”,無 “時間”。LocalDate 不承載時區信息。

java.time.LocalTime 用于表示 “本地時間”,無 “日期”。LocalTime 不承載時區信息。

java.time.LocalDateTime 用于表示 “本地日期與時間”。LocalDateTime 不承載時區信息。

LocalDate 實例與 LocalTime 實例能夠共同構建 LocalDateTime 實例,由 LocalDateTime 實例能夠獲取 LocalDate 實例與 LocalTime 實例。

由于 LocalDateTime 不承載時區信息,因此,其不能與 Instant 相互轉換,必須提供時區信息。

獲取對象的方法

獲取對象的方法:

  1. 通過靜態方法 :now()(獲取的時間是系統當前的時間
  2. 通過靜態方法:of()(方法參數可以指定時間
@Test
public void test01() {
    /* 通過靜態方法 now() 返回該類的實例 */
    //獲取當前的日期時分秒
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);

    //獲取當前的日期
    LocalDate now1 = LocalDate.now();
    System.out.println(now1);

    //獲取當前的時分秒
    LocalTime now2 = LocalTime.now();
    System.out.println(now2);

    System.out.println("=========================================");
    /* 靜態方法 of() 返回該類的實例 */
    //指定日期時分秒
    LocalDateTime localDateTime = LocalDateTime.of(2048, 11, 25, 12, 00, 30);
    System.out.println(localDateTime);

    //指定日期
    LocalDate date = LocalDate.of(2020, 12, 12);
    System.out.println(date);

    //指定時分秒
    LocalTime time = LocalTime.of(14, 20, 30);
    System.out.println(time);
}

輸出結果

2020-12-12T16:02:30.502
2020-12-12
16:02:30.502
=========================================
2048-11-25T12:00:30
2020-12-12
14:20:30

常用方法

與獲取相關的方法(get系類的方法)

  • getYear():獲取年
  • getHour():獲取小時
  • getMinute():獲取分鐘
  • getSecond():獲取秒值
  • getDayOfMonth():獲得月份天數(1-31)
  • getDayOfYear():獲得年份天數(1-366)
  • getDayOfWeek():獲得星期幾(返回一個 DayOfWeek枚舉值)
  • getMonth():獲得月份(返回一個 Month 枚舉值)
  • getMonthValue():獲得月份(1-12)
  • getYear():獲得年份
@Test
public void test02() {
    //獲取日期時分秒
    LocalDateTime now = LocalDateTime.now();

    //獲取年份
    int year = now.getYear();
    System.out.println(year);

    //獲取月份枚舉
    //Month 枚舉類,定義了十二個月份
    Month month = now.getMonth();
    System.out.println(month);

    //獲取月份的數值
    int monthValue = now.getMonthValue();
    System.out.println(monthValue);

    //獲取當天在本月的第幾天
    int dayOfMonth = now.getDayOfMonth();
    System.out.println(dayOfMonth);

    //獲取小時
    int hour = now.getHour();
    System.out.println(hour);

    //獲取分鐘
    int minute = now.getMinute();
    System.out.println(minute);

    //獲取秒值
    int second = now.getSecond();
    System.out.println(second);
}

輸出結果

2020
DECEMBER
12
12
16
2
48

轉換的方法

  • toLocalDate():將LocalDateTime轉換為相應的LocalDate對象
  • toLocalTime():將LocalDateTime轉換為相應的LocalTime對象
@Test
public void test04() {
    //獲取當前年月日,時分秒
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);

    //將LocalDateTime轉換為相應的LocalDate對象
    LocalDate localDate = now.toLocalDate();
    System.out.println(localDate);

    //將LocalDateTime轉換為相應的LocalTime對象
    LocalTime localTime = now.toLocalTime();
    System.out.println(localTime);
}

輸出結果

2020-12-12T16:07:23.045
2020-12-12
16:07:23.045

判斷的方法

  • isAfter():判斷一個日期是否在指定日期之后
  • isBefore():判斷一個日期是否在指定日期之前
  • isEqual():判斷兩個日期是否相同
  • isLeapYear():判斷是否是閏年(注意是LocalDate類 和 LocalDateTime類特有的方法)
@Test
public void test05() {
    //獲取當前的日期
    LocalDate now = LocalDate.now();

    //指定的日期
    LocalDate of = LocalDate.of(2015, 12, 12);

    //判斷一個日期是否在另一個日期之前
    boolean before = of.isBefore(now);
    System.out.println(before);

    //判斷一個日期是否在另一個日期之后
    boolean after = of.isAfter(now);
    System.out.println(after);

    //判斷這兩個日期是否相等
    boolean after1 = now.equals(of);
    System.out.println(after1);

    //判斷閏年
    boolean leapYear = of.isLeapYear();
    System.out.println(leapYear);
}

輸出結果

true
false
false
false

增減年月日時分秒的方法(plus/minus系列的方法)

增加相關的方法

  • plusYears(int offset):增加指定年份
  • plusMonths(int offset):增加指定月份
  • plusWeeks(int offset):增加指定周
  • plusDates(int offset):增加指定日
  • plusHours(int offset):增加指定時
  • plusMinuets(int offset):增加指定分
  • plusSeconds(int offset):增加指定秒
  • plusNanos(int offset):增加指定納秒

減少相關的方法

  • minusYears(int offset):減少指定年
  • minusMonths(int offset):減少指定月
  • minusWeeks(int offset):減少指定周
  • minusDates(int offset):減少指定日
  • minusHours(int offset):減少指定時
  • minusMinuets(int offset):減少指定分
  • minusSeconds(int offset):減少指定秒
  • minusNanos(int offset):減少指定納秒
@Test
public void test07() {
    //增加時間量的方法 plusXXX系類的方法 返回的是一個新的日期對象
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);
    //可以給當前的日期增加時間量
    LocalDateTime newDate = now.plusYears(1);
    int year = newDate.getYear();
    System.out.println(year);

    System.out.println("================================");
    //減去時間量的方法minusXXX 系列的方法 返回的是一個新的日期對象
    LocalDate now1 = LocalDate.now();
    System.out.println(now1);
    LocalDate newDate2 = now1.minusDays(10);
    int dayOfMonth = newDate2.getDayOfMonth();
    System.out.println(dayOfMonth);
}

輸出結果

2020-12-12T16:12:43.228
2021
================================
2020-12-12
2

指定年月日時分秒的方法

  • with(TemporalAdjuster adjuster):指定特殊時間
  • withYear(int year):指定年
  • withDayOfYear(int dayOfYear):指定日
  • withMonth(int month):指定月
  • withDayOfMonth(int dayOfMonth):指定日
@Test
public void test08() {
    //指定某個日期的方法 with()方法
    LocalDate now2 = LocalDate.now();
    System.out.println(now2);
    LocalDate localDate = now2.withYear(2014);
    System.out.println(localDate);

    // TemporalAdjusters工具類,提供了一些獲取特殊日期的方法
    LocalDate with = now2.with(TemporalAdjusters.firstDayOfMonth());
    System.out.println(with);
    LocalDate with1 = now2.with(TemporalAdjusters.firstDayOfNextMonth());
    System.out.println(with1);

    //獲取這個月的第幾個星期幾是幾號,比如 TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.FRIDAY)
    // 代表的意思是這個月的第二個星期五是幾號
    LocalDate with2 = now2.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.FRIDAY));
    System.out.println(with2);
}

輸出結果

2020-12-12
2014-12-12
2020-12-01
2021-01-01
2020-12-11

將日期格式化為字符串的方法

  • format():格式化字符串
@Test
public void test03() {
    //獲取當前日期時分秒
    LocalDateTime now = LocalDateTime.now();

    //默認格式  年-月-日T時:分:秒
    System.out.println(now);

    //指定格式
    DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH時mm分ss秒");
    //傳入格式
    String dateStr = now.format(ofPattern);
    System.out.println(dateStr);
}

輸出結果

2020-12-12T16:06:12.705
2020年12月12日 16時06分12秒

解析字符串為日期時間的方法

  • paser(String str):將一個日期字符串解析成日期對象,注意字符串日期的寫法的格式要正確,否則解析失敗
  • paser(String str, DateTimeFormatter formatter):將字符串按照參數傳入的格式進行解析
@Test
public void test06() {
    //給出一個符合默認格式要求的日期字符串
    String dateStr = "2020-01-01";

    //把日期字符串解析成日期對象 如果日期字符串時年月日 解析時用  LocalDate
    LocalDate parse = LocalDate.parse(dateStr);
    System.out.println(parse);

    System.out.println("===========================================");
    //給出一個符合默認格式要求的 時分秒 字符串
    String dateTimeStr = "14:20:30";

    //把 時分秒 字符串解析成時分秒對象
    LocalTime parse1 = LocalTime.parse(dateTimeStr);
    System.out.println(parse1);

    System.out.println("=========================================");
    //給出一個符合默認格式要求的 日期時分秒 字符串
    String str = "2018-12-12T14:20:30";

    //把 日期時分秒 字符串解析成時分秒對象
    LocalDateTime parse2 = LocalDateTime.parse(str);
    System.out.println(parse2);

    System.out.println("========================================");
    //給出一個自定義日期時分秒格式字符串
    String dateStr2 = "2020年12月12日 12:13:14";

    //給出一個自定義解析格式
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");

    //按照指定的格式去解析
    LocalDateTime parse3 = LocalDateTime.parse(dateStr2, formatter);
    System.out.println(parse3);
}

輸出結果

2020-01-01
===========================================
14:20:30
=========================================
2018-12-12T14:20:30
========================================
2020-12-12T12:13:14

TemporalAdjuster接口 - 時間調節器

前面看到的所有日期操作都是相對比較直接的。有的時候,你需要進行一些更加靈活復雜的操作,比如,將日期調整到下個周日、下個工作日,或者是本月的最后一天。這時,就需要時間調節器 TemporalAdjuster,可以更加靈活地處理日期。TemporalAdjusters 工具提供了一些通用的功能,并且你還可以新增你自己的功能。

@Test
public void testTemporalAdjuster() {
    LocalDate now = LocalDate.now();
    //指定日期
    //對于一些特殊的日期,可以通過一個工具類TemporalAdjusters 來指定
    //見名知意,本月第一天
    TemporalAdjuster temporalAdjuster = TemporalAdjusters.firstDayOfMonth();
    LocalDate with = now.with(temporalAdjuster);
    System.out.println(with);
    //下周周末
    TemporalAdjuster next = TemporalAdjusters.next(DayOfWeek.SUNDAY);
    LocalDate with1 = now.with(next);
    System.out.println(with1);
    System.out.println("===================================");


    LocalDate now1 = LocalDate.now();
    //自定義日期 - 下一個工作日
    LocalDate with2 = now1.with(new TemporalAdjuster() {
        @Override
        //參數 nowDate 當前的日期對象
        public Temporal adjustInto(Temporal nowDate) {
            //向下轉型
            LocalDate date = (LocalDate) nowDate;
            if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
                LocalDate localDate = date.plusDays(3);
                return localDate;
            } else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
                LocalDate localDate = date.plusDays(2);
                return localDate;
            } else {
                LocalDate localDate = date.plusDays(1);
                return localDate;
            }
        }
    });
    System.out.println("下一個工作日是:" + with2);
}

輸出結果

2020-12-01
2020-12-13
===================================
下一個工作日是:2020-12-14

Duration類 - 用于計算兩個“時間”間隔的類

Duration 表示一個時間段,Duration 包含兩部分:seconds 表示秒,nanos 表示納秒,它們的組合表達了時間長度。

因為 Duration 表示時間段,所以 Duration 類中不包含 now() 靜態方法。注意,Duration 不包含毫秒這個屬性。

Duration只能處理兩個LocalTime, LocalDateTime, ZonedDateTime; 如果傳入的是LocalDate,將會拋出異常

常用API

  • 靜態方法 between():計算兩個時間的間隔,默認是
  • toDays():將時間轉換為以天為單位的
  • toHours():將時間轉換為以時為單位的
  • toMinutes():將時間轉換為以分鐘為單位的
  • toMillis():將時間轉換為以毫秒為單位的
  • toNanos():將時間轉換為以納秒為單位的
@Test
public void test10() {
    //計算時間的間隔
    Instant start = Instant.now();
    for (int i = 0; i < 100000; i++) {
        // System.out.println(i);
    }
    Instant end = Instant.now();
    Duration duration = Duration.between(start, end);
    long l = duration.toNanos();

    //間隔的時間
    System.out.println("循環耗時:" + l + "納秒");
}

輸出結果

循環耗時:1000000納秒

Period類 - 用于計算兩個“日期”間隔的類

Period 在概念上和 Duration 類似,區別在于 Period 是以年月日來衡量一個時間段。Duration 用于計算兩個時間間隔,Period 用于計算兩個日期間隔,所以 between() 方法只能接收 LocalDate 類型的參數。

  • 靜態方法 between():計算兩個日期之間的間隔
  • getYears():獲取年份
  • getMonths():獲取月份
  • getDays():獲取天數
@Test
public void test11() {
    //計算兩個日期的間隔
    LocalDate birthday = LocalDate.of(2012, 12, 12);
    LocalDate now = LocalDate.now();

    //我從出生到現在,有多少歲,零幾個月,幾天
    //計算兩個日期的間隔
    Period between = Period.between(birthday, now);
    int years = between.getYears();
    int months = between.getMonths();
    int days = between.getDays();
    System.out.println("瑪雅人的地球都消滅了" + years + "年" + months + "月" + days + "天了...");
}

輸出結果

瑪雅人的地球都消滅了8年0月0天了...

Instant 時間戳類

java.time.Instant 時間線上的一個瞬時點,承載納秒級精度的 Unix 時間戳,其 String toString() 方法基于 ISO-8601 進行格式化。Instant 不承載時區信息。

獲取對象的方法:now():注意默認獲取出來的是默認時區,和我們相差八個小時(因為我們在東八時區

設置偏移量的方法:atOffset()

獲取系統默認時區時間的方法:atZone():方法的參數是要一個時區的編號(可以通過時區編號類獲取ZonedDateTime類的對象)

get系列的方法

  • getEpochSecond():獲取從1970-01-01 00:00:00當前時間秒值
  • toEpochMilli():獲取從1970-01-01 00:00:00當前時間毫秒值
  • getNano():把獲取到的當前時間的秒數 換算成納秒

ofEpoch系列方法

  • ofEpochSecond():給計算機元年增加秒數
  • ofEpochMilli():給計算機元年增加毫秒數
@Test
public void test09() {
    //  Instant 時間戳類從1970 -01 - 01 00:00:00 截止到當前時間的毫秒值
    Instant now = Instant.now();
    System.out.println(now); //獲取的是默認時區,獲取的不是中國 的時區

    //獲取當前時區的,我們可以添加偏移量,返回偏移過后的日期
    OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));
    System.out.println(offsetDateTime);
    System.out.println("===========================");

    //從1970 - 01 - 01 00:00:00 截止到當前時間的毫秒值
    long l = System.currentTimeMillis();
    System.out.println(l);
    long time = new Date().getTime();
    System.out.println(time);

    //JDK1.8 Instant 時間戳類從1970 -01 - 01 00:00:00 截止到當前時間的毫秒值
    Instant now1 = Instant.now();

    //toEpochMilli():從1970 -01 - 01 00:00:00 截止到當前時間間隔的毫秒值
    long l1 = now1.toEpochMilli();
    System.out.println(l1);

    //獲取從1970 -01 - 01 00:00:00 截止到當前時間間隔的秒值
    long epochSecond = now1.getEpochSecond();
    System.out.println(epochSecond);

    System.out.println("==========================");
    //給計算機元年增加相應的時間量
    Date date = new Date(1000 * 60 * 60 * 24);
    System.out.println(date);

    //現在 給計算機元年增加相應的時間量
    //5. ofEpochSecond() 方法 給計算機元年增加秒數
    //ofEpochMilli() 給計算機元年增加毫秒數
    Instant instant = Instant.ofEpochMilli(1000 * 60 * 60 * 24);
    System.out.println(instant);

    //ofEpochSecond() 方法 給計算機元年增加秒數
    Instant instant1 = Instant.ofEpochSecond(60 * 60 * 24);
    System.out.println(instant1);
}

輸出結果

2020-12-12T08:48:46.480Z
2020-12-12T16:48:46.480+08:00
===========================
1607762926539
1607762926540
1607762926540
1607762926
==========================
Fri Jan 02 08:00:00 CST 1970
1970-01-02T00:00:00Z
1970-01-02T00:00:00Z

Clock - 時鐘系統

Clock 是時鐘系統,用于查找當前時刻。你可以用它來獲取某個時區下當前的日期或者時間。可以用 Clock 來替代舊的 System.currentTimeInMillis() 與 TimeZone.getDefault() 方法。

@Test
public void testClock() {
    //系統默認時間
    Clock clock = Clock.systemDefaultZone();
    System.out.println(clock.instant().toString());

    //世界協調時UTC
    Clock clock1 = Clock.systemUTC();
    //通過Clock獲取當前時刻
    System.out.println("當前時刻為:" + clock1.instant());
    //獲取clock對應的毫秒數,與System.currentTimeMillis()輸出相同
    System.out.println(clock1.millis());
    System.out.println(System.currentTimeMillis());
    System.out.println(new Date(System.currentTimeMillis()).toString());

    //在clock基礎上增加6000秒,返回新的Clock
    Clock clock2 = Clock.offset(clock1, Duration.ofSeconds(6000));

    //紐約時間
    Clock clock3 = Clock.system(ZoneId.of("America/New_York"));
    System.out.println("Current DateTime with NewYork clock: " + LocalDateTime.now(clock3));
    System.out.println(clock3.millis());
}

輸出結果

2020-12-12T09:05:07.025Z
當前時刻為:2020-12-12T09:05:07.036Z
1607763907036
1607763907036
Sat Dec 12 17:05:07 CST 2020
Current DateTime with NewYork clock: 2020-12-12T04:05:07.040
1607763907041

ZonedDate、ZonedTime、ZonedDateTime - 帶時區的日期時間

這個三個類方法及用法和 LocalDate、 LocalTime、 LocalDateTime 基本一樣,只不過ZonedDate、ZonedTime、ZonedDateTime 這三個帶有特定時區

ZoneId - 世界時區類

Java 使用 ZoneId 來標識不同的時區。時區從基準 UTC 開始的一個固定偏移。ZoneId 的子類 ZoneOffset,代表了這種從倫敦格林威治零度子午線開始的時間偏移,也就是時差。

常用API

  • getAvailableZoneIds():獲取世界各個地方的時區的集合
  • systemDefault():獲取系統默認時區的ID
  • of(String zoneName):根據各個地區的時區ID名創建對象
@Test
public void test13() {
    //ZoneID 世界時區類
    //獲取世界各地的時區編號。
    Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
    for (String availableZoneId : availableZoneIds) {
        System.out.println(availableZoneId);
    }

    System.out.println("=====================");
    //獲取系統的默認時區編號
    ZoneId zoneId = ZoneId.systemDefault();
    System.out.println(zoneId);

    //獲取其他國家的日期
    LocalDateTime now = LocalDateTime.now();
    //獲取指定時區的日期時間
    ZoneId zoneId1 = ZoneId.of("Europe/Monaco");
    ZonedDateTime zonedDateTime = now.atZone(zoneId1);  //獲得指定時區的當前時間
    System.out.println(zonedDateTime);

    System.out.println("=====================");
    //根據時區,獲取該地區的日期
    LocalDateTime now1 = LocalDateTime.now(ZoneId.of("America/Phoenix"));  //獲得指定時區的當前時間(不帶時區信息)
    System.out.println(now1);
}

輸出結果

America/Toronto
Asia/Singapore
Australia/Lindeman
America/Los_Angeles
SystemV/EST5EDT
Pacific/Majuro
America/Argentina/Buenos_Aires
Europe/Nicosia
Pacific/Guadalcanal
Europe/Athens
US/Pacific
Europe/Monaco
=====================
Asia/Shanghai
2020-12-12T20:56:27.214+01:00[Europe/Monaco]
=====================
2020-12-12T05:56:27.225

DateTimeFormatter類 - 用于解析日期字符串和格式化日期輸出

DateTimeFormatter用于解析日期字符串和格式化日期輸出,創建格式化器最簡單的方法是通過 DateTimeFormatter 的靜態工廠方法以及常量。

在java8之前,我們進行時間格式化主要是使用SimpleDateFormat,而在java8中,主要是使用DateTimeFormatter,java8中,預定義了一些標準的時間格式,我們可以直接將時間轉換為標準的時間格式

常用API

  • ofPattern(“yyyy-MM-dd”):靜態方法,通過給定格式獲取對象
  • format():把一個日期對象的默認格式 格式化成指定的格式字符串
@Test
public void test12() {
    // 之前格式化日期的類  new SimpleDateFormat()
    //JDK1.8 DateTimeFormatter
    //指定格式 靜態方法 ofPattern()
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    // DateTimeFormatter 自帶的格式方法
    LocalDateTime now = LocalDateTime.now();

    //把日期對象,格式化成字符串
    String format = formatter.format(now);
    //剛才的方式是使用的日期自帶的格式化方法
    String format1 = now.format(formatter);
    System.out.println(format);
    System.out.println(format1);
}

輸出結果

2020-12-12 17:28:50
2020-12-12 17:28:50

格式化輸出 & 字符串解析

java.time.format.DateTimeFormatter 能夠進行 TemporalAccessor 類型(包括:LocalDateLocalTimeLocalDateTimeZonedDateTime)的格式化輸出。同時,LocalDateLocalTimeLocalDateTimeZonedDateTime 提供了靜態的 parse 方法,能夠進行字符串解析。

LocalDateLocalTimeLocalDateTimeZonedDateTime 允許基于類型的默認格式進行格式化輸出和字符串解析。

類型 默認格式示例
Instant 2017-11-23T10:15:30.00Z
LocalDate 2017-11-23
LocalTime 10:15:30
LocalDateTime 2017-11-23T10:15:30
ZonedDateTime 2017-11-23T10:15:30+01:00[Asia/Shanghai]

使用SimpleDateFormat的正確姿勢

方法一:在需要執行格式化的地方都新建SimpleDateFormat實例,使用局部變量來存放SimpleDateFormat實例

public static String formatDate(Date date) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return sdf.format(date);
}

這種方法可能會導致短期內創建大量的SimpleDateFormat實例,如解析一個excel表格里的字符串日期。

方法二:為了避免創建大量的SimpleDateFormat實例,往往會考慮把SimpleDateFormat實例設為靜態成員變量,共享SimpleDateFormat對象。這種情況下就得對SimpleDateFormat添加同步。

private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

public static String formatDate(Date date) {
    synchronized (sdf) {
        return sdf.format(date);
    }
}

這種方法的缺點也很明顯,就是在高并發的環境下會導致解析被阻塞。

方法三(推薦):要在高并發環境下能有比較好的體驗,可以使用ThreadLocal來限制SimpleDateFormat只能在線程內共享,這樣就避免了多線程導致的線程安全問題。

private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};

public static String formatDate(Date date) {
    return threadLocal.get().format(date);
}

Java8 日期時間類與Date類的相互轉化

在轉換中,我們需要注意,因為java8之前Date是包含日期和時間的,而LocalDate只包含日期,LocalTime只包含時間,所以與Date在互轉中,勢必會丟失日期或者時間,或者會使用起始時間。如果轉LocalDateTime,那么就不存在信息誤差。

Date和Instant互相轉換

@Test
public void test18() {
    //Date與Instant互相轉換
    Instant instant  = Instant.now();
    Date date = Date.from(instant);
    System.out.println(date);

    Instant instant2 = date.toInstant();
    System.out.println(instant2);
}

輸出結果

Sat Dec 12 21:18:13 CST 2020
2020-12-12T13:18:13.129Z

Date與LocalDateTime互相轉換

@Test
public void test19() {
    //Date - LocalDateTime
    Date date = new Date();
    System.out.println("current date: " + date);

    LocalDateTime localDateTime1 = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    System.out.println("localDateTime1: " + localDateTime1);

    LocalDateTime localDateTime2 = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    System.out.println("localDateTime2: " + localDateTime2);

    //LocalDateTime - Date
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println("localDateTime: " + localDateTime);

    Date date1 = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    System.out.println("date1: " + date1);
}

輸出結果

current date: Sat Dec 12 21:27:47 CST 2020
localDateTime1: 2020-12-12T21:27:47.592
localDateTime2: 2020-12-12T21:27:47.592
localDateTime: 2020-12-12T21:27:47.652
date1: Sat Dec 12 21:27:47 CST 2020

Date與LocalDate互相轉換

@Test
public void test20() {
    Date date = new Date();
    System.out.println("current date: " + date);

    // Date -LocalDate
    LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    System.out.println("localDate: " + localDate);

    // LocalDate -Date
    LocalDate localDate1 = LocalDate.now();
    //因為LocalDate不包含時間,所以轉Date時,會默認轉為當天的起始時間,00:00:00
    Instant instant = localDate1.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
    Date date1 = Date.from(instant);
    System.out.println("date1: " + date1);
}

輸出結果

current date: Sat Dec 12 21:37:51 CST 2020
localDate: 2020-12-12
date1: Sat Dec 12 00:00:00 CST 2020

Date轉換為LocalTime

@Test
public void test21() {
    Date date = new Date();
    System.out.println("current date: " + date);

    // Date - LocalTime
    LocalTime localTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
    System.out.println("localTime: " + localTime);
}

輸出結果

current date: Sat Dec 12 21:40:47 CST 2020
localTime: 21:40:47.596

GregorianCalendar與ZonedDateTime相互轉換

@Test
public void test22() {
    //GregorianCalendar與ZonedDateTime相互轉換
    ZonedDateTime zonedDateTime = new GregorianCalendar().toZonedDateTime();
    System.out.println("zonedDateTime: " + zonedDateTime);
    GregorianCalendar calendar = GregorianCalendar.from(zonedDateTime);
    System.out.println("calendar: " + calendar.getTime());
}

輸出結果

zonedDateTime: 2020-12-12T21:55:08.286+08:00[Asia/Shanghai]
calendar: Sat Dec 12 21:55:08 CST 2020

Java 8日期時間類圖

img

類圖所示,java.time.temporal 提供的接口:

  1. TemporalField:日期與時間 “字段”,例如:2017-11-18 中的 18 “天”
  2. TemporalUnit:時間 “單位”,例如:1 年 13 天的 13 “天”
  3. TemporalAccessor:“時間相關” 對象的 “只讀” 接口
  4. Temporal:“時間相關” 對象的 “讀寫” 接口,繼承自 TemporalAccessor
  5. TemporalAdjusterTemporal 類型對象 “設置 & 調整” 的函數式接口
  6. TemporalAmount:時間段

java.time 提供的類:

  1. InstantLocalDateLocalTimeLocalDateTimeZonedDateTime:實現 TemporalTemporalAdjuster 接口
  2. DurationPeriod:實現 TemporalAmount 接口

Java 8時間日期 API 中的設計模式

  • 工廠模式:now()、of() 等工廠方法直接生成日期或者日期時間。

  • 策略模式:LocalDate/LocalTime/LocalDateTime/ZonedDateTime,針對日期、時間、日期和時間、帶時區的日期時間,使用具體的時間日期類處理。策略模式在設計一整套東西時,對開發者特別友好。

    前面也提到,所有新的日期時間 API 類都實現了一系列方法用以完成通用的任務,如:加、減、格式化、解析、從日期/時間中提取單獨部分。一旦你使用了其中某個類的方法,那么非常容易上手其他類的使用。

  • 構建者模式:Java 8 開始在 Calendar 中加入了構建者類,可以按如下方式生成新的 Calendar 對象。

這里設計模式與標準的教科書式的設計模式可能有所區別,所以我們在使用設計模式時也應靈活處理,不是一成不變的。

Java 8的日期時間API總結

前面詳細介紹了Java 8的日期時間API,現在進行簡單總結一下。

新的時間與日期 API 中很重要的一點是,它定義清楚了基本的時間與日期的概念,比方說日期、時間、瞬時時間、持續時間、時區及時間段。它們都是基于 ISO8601 日歷系統,它是世界民用歷法,也就是我們所說的公歷。

java.time包下主要包含下面幾個主要的類:

  • LocalDate:表示不帶時間的日期,比如:2016-10-20
  • LocalTime:表示不帶日期的時間,比如:23:12:10
  • LocalDateTime:日期時間,比如:2016-10-20 23:14:21
  • TemporalAdjuster : 時間調節器
  • TemporalAdjusters:獲得指定日期時間等,如當月的第一天、今年的最后一天等
  • Duration:持續時間,計算兩個“時間”的間隔
  • Period:日期間隔,計算兩個“日期”的間隔
  • Instant:Unix 時間,它代表的是時間戳,比如 2018-01-14T02:20:13.592Z
  • Clock:時鐘,獲取某個時區下的瞬時時間
  • ZoneId:時區id,例如 Asia/Shanghai
  • ZonedDateTime:帶時區的日期時間
  • DateTimeFormatter:時間格式化

新的 API 區分各種日期時間概念并且各個概念使用相似的方法定義模式,這種相似性非常有利于 API 的學習。總結一下一般的方法規律:

  • of:靜態工廠方法,用于創建實例
  • now:靜態工廠方法,用當前時間創建實例
  • parse:靜態工廠方法,從字符串解析得到對象實例
  • get:獲取對象的部分狀態
  • is:檢查某些東西的是否是 true,例如比較時間前后
  • with:返回一個部分狀態改變了的時間日期對象拷貝(單獨一個with方法,參數為TemporalAdjusters類型)
  • plus:返回一個時間增加了的時間日期對象拷貝
  • minus:返回一個時間減少了的時間日期對象拷貝
  • to:把當前時間日期對象轉換成另外一個,可能會損失部分狀態。
  • at:把這個對象與另一個對象組合起來,例如:date.atTime(time)
  • format:將時間日期格式化為字符串

最后再次聲明,Java 8 中新的時間與日期 API 中的所有類都是不可變且線程安全的,任何修改操作都會返回一個新的實例,而之前 java.util.Date、Calendar 以及 SimpleDateFormat 這些關鍵的類都不是線程安全的。

作者:ThinkWon 發表于 2020/12/12 23:56:51 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/111087199
閱讀:991 評論:4 查看評論
]]>
<![CDATA[[原]史上最全Java7日期時間工具類]]> http://www.gifted-edu.com/ThinkWon/article/details/110779441 http://www.gifted-edu.com/ThinkWon/article/details/110779441 ThinkWon 2020/12/06 22:11:51

文章目錄

這是我總結的Java7日期工具類,應該是比較全面的,滿足日常開發絕大部分需求,分享給大家,有錯誤之處,還望大神指教。

/**
 * 日期時間工具類
 *
 * @author JourWon
 * @date 2020/12/5
 */
public class DateUtils {

    /**
     * 顯示年月日時分秒,例如 2015-08-11 09:51:53.
     */
    public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 顯示年月日時分,例如 2015-08-11 09:51.
     */
    public static final String NO_SECOND_DATETIME_PATTERN = "yyyy-MM-dd HH:mm";

    /**
     * 僅顯示年月日,例如 2015-08-11.
     */
    public static final String DATE_PATTERN = "yyyy-MM-dd";

    /**
     * 僅顯示時分秒,例如 09:51:53.
     */
    public static final String TIME_PATTERN = "HH:mm:ss";

    /**
     * 顯示年月日時分秒(由/分割),例如 2015/08/11 09:51:53.
     */
    public static final String DATETIME_PATTERN_WITH_SLASH = "yyyy/MM/dd HH:mm:ss";

    /**
     * 顯示年月日(由/分割),例如 2015/08/11.
     */
    public static final String DATE_PATTERN_WITH_SLASH = "yyyy/MM/dd";

    /**
     * 顯示年月日時分秒(無符號),例如 20150811095153.
     */
    public static final String UNSIGNED_DATETIME_PATTERN = "yyyyMMddHHmmss";

    /**
     * 僅顯示年月日(無符號),例如 20150811.
     */
    public static final String UNSIGNED_DATE_PATTERN = "yyyyMMdd";

    /**
     * 僅顯示年(無符號),例如 2015.
     */
    private static final String YEAR_PATTERN = "yyyy";

    /**
     * 僅顯示年月,例如 2015-08.
     */
    private static final String MONTH_PATTERN = "yyyy-MM";

    /**
     * 僅顯示年月(無符號),例如 201508.
     */
    private static final String UNSIGNED_MONTH_PATTERN = "yyyyMM";

    /**
     * 一天的開始時間,僅顯示時分秒
     */
    private static final String START_TIME = "00:00:00";

    /**
     * 一天的結束時間,僅顯示時分秒
     */
    private static final String END_TIME = "23:59:59";

    /**
     * 每天的毫秒數.
     */
    public static final long MILLISECONDS_PER_DAY = 86400000L;

    /**
     * 每小時毫秒數.
     */
    public static final long MILLISECONDS_PER_HOUR = 3600000L;

    /**
     * 每分鐘毫秒數.
     */
    public static final long MILLISECONDS_PER_MINU = 60000L;

    /**
     * 每秒的毫秒數.
     */
    public static final long MILLISECONDS_PER_SECONDS = 1000L;

    /**
     * 每分鐘秒數.
     */
    public static final long SECONDS_PER_MINUTE = 60L;

    /**
     * 每小時秒數.
     */
    public static final long SECONDS_PER_HOUR = 3600L;

    /**
     * 每天秒數.
     */
    public static final long SECONDS_PER_DAY = 86400L;

    /**
     * 每周秒數.
     */
    public static final long SECONDS_PER_WEEK = 604800L;

    /**
     * 每個月秒數,默認每月30天.
     */
    public static final long SECONDS_PER_MONTH = 2592000L;

    /**
     * 每年秒數,默認每年365天.
     */
    public static final long SECONDS_PER_YEAR = 31536000L;

    /**
     * 每周的天數.
     */
    public static final long DAYS_PER_WEEK = 7L;

    /**
     * 春天;
     */
    public static final Integer SPRING = 1;

    /**
     * 夏天;
     */
    public static final Integer SUMMER = 2;

    /**
     * 秋天;
     */
    public static final Integer AUTUMN = 3;

    /**
     * 冬天;
     */
    public static final Integer WINTER = 4;

    /**
     * 星期日;
     */
    public static final String SUNDAY = "星期日";

    /**
     * 星期一;
     */
    public static final String MONDAY = "星期一";

    /**
     * 星期二;
     */
    public static final String TUESDAY = "星期二";

    /**
     * 星期三;
     */
    public static final String WEDNESDAY = "星期三";

    /**
     * 星期四;
     */
    public static final String THURSDAY = "星期四";

    /**
     * 星期五;
     */
    public static final String FRIDAY = "星期五";

    /**
     * 星期六;
     */
    public static final String SATURDAY = "星期六";

    /**
     * 獲取當前日期和時間字符串.
     *
     * @return String 日期時間字符串,例如 2015-08-11 09:51:53
     */
    public static String getDateTimeStr() {
        return format(new Date(), DATETIME_PATTERN);
    }

    /**
     * 獲取當前日期字符串.
     *
     * @return String 日期字符串,例如2015-08-11
     */
    public static String getDateStr() {
        return format(new Date(), DATE_PATTERN);
    }

    /**
     * 獲取當前時間字符串.
     *
     * @return String 時間字符串,例如 09:51:53
     */
    public static String getTimeStr() {
        return format(new Date(), TIME_PATTERN);
    }

    /**
     * 獲取當前年份字符串.
     *
     * @return String 當前年份字符串,例如 2015
     */
    public static String getYearStr() {
        return format(new Date(), YEAR_PATTERN);
    }

    /**
     * 獲取當前月份字符串.
     *
     * @return String 當前月份字符串,例如 08
     */
    public static String getMonthStr() {
        return format(new Date(), "MM");
    }

    /**
     * 獲取當前天數字符串.
     *
     * @return String 當前天數字符串,例如 11
     */
    public static String getDayStr() {
        return format(new Date(), "dd");
    }

    /**
     * 獲取當前星期字符串.
     *
     * @return String 當前星期字符串,例如 星期二
     */
    public static String getDayOfWeekStr() {
        return format(new Date(), "E");
    }

    /**
     * 獲取指定日期是星期幾
     *
     * @param date 日期
     * @return String 星期幾
     */
    public static String getDayOfWeekStr(Date date) {
        String[] weekOfDays = {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY};
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int num = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        return weekOfDays[num];
    }

    /**
     * 獲取當前小時字符串.
     *
     * @return String 當前小時字符串,例如09
     */
    public static String getHourStr() {
        return format(new Date(), "HH");
    }

    /**
     * 獲取當前分鐘字符串.
     *
     * @return String 當前分鐘字符串,例如51
     */
    public static String getMinuteStr() {
        return format(new Date(), "mm");
    }

    /**
     * 獲取當前秒鐘字符串.
     *
     * @return String 當前秒鐘字符串,例如53
     */
    public static String getSecondStr() {
        return format(new Date(), "ss");
    }

    /**
     * 獲取日期時間字符串
     *
     * @param date    需要轉化的日期時間
     * @param pattern 時間格式
     * @return String 日期時間字符串,例如 2015-08-11 09:51:53
     */
    public static String format(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 時間戳轉換為日期時間字符串
     *
     * @param timestamp 時間戳
     * @param pattern   日期格式 例如DATETIME_PATTERN
     * @return String 日期時間字符串,例如 2015-08-11 09:51:53
     */
    public static String getDateTimeStr(long timestamp, String pattern) {
        return new SimpleDateFormat(pattern).format(timestamp);
    }

    /**
     * 日期字符串轉換為日期(java.util.Date)
     *
     * @param dateStr 日期字符串
     * @param pattern 日期格式 例如DATETIME_PATTERN
     * @return Date 日期
     */
    public static Date parse(String dateStr, String pattern) {
        Date date = null;
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        // 設置lenient為false. 否則SimpleDateFormat會比較寬松地驗證日期,比如2007/02/29會被接受,并轉換成2007/03/01
        dateFormat.setLenient(false);
        try {
            date = dateFormat.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 獲取指定日期num年數之后的日期.
     *
     * @param num 間隔年數(負數表示之前)
     * @return Date 日期
     */
    public static Date addYears(Date date, int num) {
        return add(date, num, Calendar.YEAR);
    }

    /**
     * 獲取當前日期指定年數之后的日期.
     *
     * @param num 間隔年數(負數表示之前)
     * @return Date 日期
     */
    public static Date addYears(int num) {
        return add(new Date(), num, Calendar.YEAR);
    }

    /**
     * 獲取當前日期num月數之后的日期.
     *
     * @param num 間隔月數(負數表示之前)
     * @return Date 日期
     */
    public static Date addMonths(Date date, int num) {
        return add(date, num, Calendar.MONTH);
    }

    /**
     * 獲取當前日期指定月數之后的日期.
     *
     * @param num 間隔月數(負數表示之前)
     * @return Date 日期
     */
    public static Date addMonths(int num) {
        return add(new Date(), num, Calendar.MONTH);
    }

    /**
     * 獲取指定日期num周數之后的日期.
     *
     * @param date 日期
     * @param num  周數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addWeeks(Date date, int num) {
        return add(date, num, Calendar.WEEK_OF_YEAR);
    }

    /**
     * 獲取當前日期指定周數之后的日期.
     *
     * @param num 周數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addWeeks(int num) {
        return add(new Date(), num, Calendar.WEEK_OF_YEAR);
    }

    /**
     * 獲取指定日期num天數之后的日期.
     *
     * @param date 日期
     * @param num  天數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addDays(Date date, int num) {
        return add(date, num, Calendar.DAY_OF_MONTH);
    }

    /**
     * 獲取當前日期指定天數之后的日期.
     *
     * @param num 天數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addDays(int num) {
        return add(new Date(), num, Calendar.DAY_OF_MONTH);
    }

    /**
     * 獲取指定日期num小時之后的日期.
     *
     * @param date 日期
     * @param num  小時數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addHours(Date date, int num) {
        return add(date, num, Calendar.HOUR_OF_DAY);
    }

    /**
     * 獲取當前日期指定小時之后的日期.
     *
     * @param num 小時數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addHours(int num) {
        return add(new Date(), num, Calendar.HOUR_OF_DAY);
    }

    /**
     * 獲取指定日期num分鐘之后的日期.
     *
     * @param date 日期
     * @param num  分鐘數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addMinutes(Date date, int num) {
        return add(date, num, Calendar.MINUTE);
    }

    /**
     * 獲取當前日期指定分鐘之后的日期.
     *
     * @param num 分鐘數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addMinutes(int num) {
        return add(new Date(), num, Calendar.MINUTE);
    }

    /**
     * 獲取指定日期num秒鐘之后的日期.
     *
     * @param date 日期
     * @param num  秒鐘數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addSeconds(Date date, int num) {
        return add(date, num, Calendar.SECOND);
    }

    /**
     * 獲取當前日期指定秒鐘之后的日期.
     *
     * @param num 秒鐘數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addSeconds(int num) {
        return add(new Date(), num, Calendar.SECOND);
    }

    /**
     * 獲取指定日期num毫秒之后的日期.
     *
     * @param date 日期
     * @param num  毫秒數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addMilliSeconds(Date date, int num) {
        return add(date, num, Calendar.MILLISECOND);
    }

    /**
     * 獲取當前日期指定毫秒之后的日期.
     *
     * @param num 毫秒數(負數表示之前)
     * @return Date 新的日期
     */
    public static Date addMilliSeconds(int num) {
        return add(new Date(), num, Calendar.MILLISECOND);
    }

    /**
     * 獲取當前日期指定數量日期時間單位之后的日期.
     *
     * @param date 日期
     * @param num  數量
     * @param unit 日期時間單位
     * @return Date 新的日期
     */
    public static Date add(Date date, int num, int unit) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(unit, num);
        return calendar.getTime();
    }

    /**
     * 計算兩個日期之間相隔年數.
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @return int 相隔年數,向下取整
     */
    public static int getYearsBetween(Date startDate, Date endDate) {
        return getMonthsBetween(startDate, endDate) / 12;
    }

    /**
     * 計算兩個日期之間相隔月數.
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @return int 相隔月數,向下取整
     */
    public static int getMonthsBetween(Date startDate, Date endDate) {
        int months;
        int flag = 0;

        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);

        if (endCalendar.equals(startCalendar)) {
            return 0;
        }

        if (startCalendar.after(endCalendar)) {
            Calendar temp = startCalendar;
            startCalendar = endCalendar;
            endCalendar = temp;
        }
        if (endCalendar.get(Calendar.DAY_OF_MONTH) < startCalendar.get(Calendar.DAY_OF_MONTH)) {
            flag = 1;
        }

        if (endCalendar.get(Calendar.YEAR) > startCalendar.get(Calendar.YEAR)) {
            months = ((endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR))
                    * 12 + endCalendar.get(Calendar.MONTH) - flag)
                    - startCalendar.get(Calendar.MONTH);
        } else {
            months = endCalendar.get(Calendar.MONTH)
                    - startCalendar.get(Calendar.MONTH) - flag;
        }

        return months;
    }

    /**
     * 計算兩個日期之間相隔周數.
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @return long 相隔周數,向下取整
     */
    public static long getWeeksBetween(Date startDate, Date endDate) {
        return getDaysBetween(startDate, endDate) / DAYS_PER_WEEK;
    }

    /**
     * 計算兩個日期之間相隔天數.
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @return long 相隔天數,向下取整
     */
    public static long getDaysBetween(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_DAY;
    }

    /**
     * 計算兩個日期之間相隔小時數.
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @return long 相隔小時數,向下取整
     */
    public static long getHoursBetween(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_HOUR;
    }

    /**
     * 計算兩個日期之間相隔分鐘數.
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @return long 相隔分鐘數,向下取整
     */
    public static long getMinutesBetween(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_MINU;
    }

    /**
     * 計算兩個日期之間相隔秒數.
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @return long 相隔秒數,向下取整
     */
    public static long getSecondsBetween(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_SECONDS;
    }

    /**
     * 獲取當前季度.
     * 注意:3~5月為春季 1,6~8月為夏季 2,9~11月為秋季 3,12~2月為冬季 4
     *
     * @return int 當前季度數
     */
    public static int getCurrentSeason() {
        Calendar calendar = Calendar.getInstance();
        int month = calendar.get(Calendar.MONTH) + 1;
        int season = 0;
        if (month >= 3 && month <= 5) {
            season = SPRING;
        } else if (month >= 6 && month <= 8) {
            season = SUMMER;
        } else if (month >= 9 && month <= 11) {
            season = AUTUMN;
        } else if (month == 12 || month >= 1 && month <= 2) {
            season = WINTER;
        }
        return season;
    }

    /**
     * 獲取當前日期與之前日期的時間間隔.
     *
     * @param date 之前的日期
     * @return String 例如 16分鐘前、2小時前、3天前、4月前、5年前等
     */
    public static String getIntervalByDate(Date date) {
        long secondsBetween = getSecondsBetween(date, new Date());
        return getIntervalBySeconds(secondsBetween);
    }

    /**
     * 將以秒為單位的時間轉換為其他單位.
     *
     * @param seconds 秒數
     * @return String 例如 16分鐘前、2小時前、3天前、4月前、5年前等
     */
    public static String getIntervalBySeconds(long seconds) {
        StringBuffer buffer = new StringBuffer();
        if (seconds < SECONDS_PER_MINUTE) {
            buffer.append(seconds).append("秒前");
        } else if (seconds < SECONDS_PER_HOUR) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_MINUTE)).append("分鐘前");
        } else if (seconds < SECONDS_PER_DAY) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_HOUR)).append("小時前");
        } else if (seconds < SECONDS_PER_WEEK) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_DAY)).append("天前");
        } else if (seconds < SECONDS_PER_MONTH) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_WEEK)).append("周前");
        } else if (seconds < SECONDS_PER_YEAR) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_MONTH)).append("月前");
        } else {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_YEAR)).append("年前");
        }
        return buffer.toString();
    }

    /**
     * 將 Date 日期轉化為 Calendar 類型日期.
     *
     * @param date 指定日期
     * @return Calendar Calendar對象
     */
    public static Calendar getCalendar(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * 得到UTC時間,類型為字符串,格式為"yyyy-MM-dd HH:mm"
     * 如果獲取失敗,返回null
     *
     * @return
     */
    public static String getUTCTimeStr() {
        StringBuffer UTCTimeBuffer = new StringBuffer();
        // 1、取得本地時間:
        Calendar cal = Calendar.getInstance();
        // 2、取得時間偏移量:
        int zoneOffset = cal.get(Calendar.ZONE_OFFSET);
        // 3、取得夏令時差:
        int dstOffset = cal.get(Calendar.DST_OFFSET);
        // 4、從本地時間里扣除這些差量,即可以取得UTC時間:
        cal.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        UTCTimeBuffer.append(year).append("-").append(month).append("-").append(day);
        UTCTimeBuffer.append(" ").append(hour).append(":").append(minute);
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(NO_SECOND_DATETIME_PATTERN);
            sdf.parse(UTCTimeBuffer.toString());
            return UTCTimeBuffer.toString();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 將Timestamp轉換為yyyy-MM-dd HH:mm:ss格式字符串
     *
     * @param timestamp
     * @return
     */
    public static String timestampToStr(Timestamp timestamp) {
        return timestamp.toString().substring(0, 19);
    }

    /**
     * 比較傳進來的日期是否大于當前日期,如果傳進來的日期大于當前日期則返回true,否則返回false
     *
     * @param dateStr 日期字符串
     * @param pattern 日期格式
     * @return boolean
     */
    public static boolean compareNowDate(String dateStr, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        try {
            Date date = simpleDateFormat.parse(dateStr);
            return date.after(new Date());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 如果endDateStr>startDateStr,返回true,否則返回false
     *
     * @param startDateStr 開始日期字符串
     * @param endDateStr   結束日期字符串
     * @param pattern      日期格式
     * @return boolean
     */
    public static boolean compareDate(String startDateStr, String endDateStr, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        try {
            Date startDate = simpleDateFormat.parse(startDateStr);
            Date endDate = simpleDateFormat.parse(endDateStr);
            return endDate.after(startDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 如果startDate>endDate,返回true,否則返回false
     *
     * @param startDate 開始日期字符串
     * @param endDate   結束日期字符串
     * @return boolean
     */
    public static boolean compareDate(Date startDate, Date endDate) {
        return endDate.after(startDate);
    }

    /**
     * 判斷日期是否合法
     *
     * @param dateStr yyyy-MM-dd HH:mm:ss格式日期字符串
     * @return
     */
    public static boolean isValidDate(String dateStr) {
        boolean convertSuccess = true;
        // 指定日期格式為四位年/兩位月份/兩位日期
        SimpleDateFormat format = new SimpleDateFormat(DATETIME_PATTERN);
        try {
            // 設置lenient為false. 否則SimpleDateFormat會比較寬松地驗證日期,比如2007/02/29會被接受,并轉換成2007/03/01
            format.setLenient(false);
            format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
            // 如果throw java.text.ParseException或者NullPointerException,就說明格式不對
            convertSuccess = false;
        }
        return convertSuccess;
    }

    /**
     * 判斷日期是否為月底最后一天
     *
     * @param date 日期
     * @return boolean true:是  false:否
     */
    public static boolean isLastDayofMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
        if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
            return true;
        }
        return false;
    }

    /**
     * 獲取本年第一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getYearStartTimeStr() {
        return getDateTimeStr(getStartDayOfYear(new Date()));
    }

    /**
     * 獲取指定日期當年第一天的日期字符串
     *
     * @param date
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getYearStartTimeStr(Date date) {
        return getDateTimeStr(getStartDayOfYear(date));
    }

    /**
     * 獲取本年最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getYearEndTimeStr() {
        return getDateTimeStr(getEndDayOfYear(new Date()));
    }

    /**
     * 獲取指定日期當年最后一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getYearEndTimeStr(Date date) {
        return getDateTimeStr(getEndDayOfYear(date));
    }

    /**
     * 獲取本月第一天的日期字符串
     * 格式:yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String getMonthStartTimeStr() {
        return getDateTimeStr(getStartDayOfMonth(new Date()));
    }

    /**
     * 獲取指定日期當月第一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getMonthStartTimeStr(Date date) {
        return getDateTimeStr(getStartDayOfMonth(date));
    }

    /**
     * 獲取本月最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getMonthEndTimeStr() {
        return getDateTimeStr(getEndDayOfMonth(new Date()));
    }

    /**
     * 獲取指定日期當月最后一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getMonthEndTimeStr(Date date) {
        return getDateTimeStr(getEndDayOfMonth(date));
    }

    /**
     * 獲取本周第一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekStartTimeStr() {
        return getDateTimeStr(getStartDayOfWeek(new Date()));
    }

    /**
     * 獲取指定日期當周第一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekStartTimeStr(Date date) {
        return getDateTimeStr(getStartDayOfWeek(date));
    }

    /**
     * 獲取本周最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekEndTimeStr() {
        return getDateTimeStr(getEndDayOfWeek(new Date()));
    }

    /**
     * 獲取指定日期當周最后一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekEndTimeStr(Date date) {
        return getDateTimeStr(getEndDayOfWeek(date));
    }

    /**
     * 獲取今天的開始時間字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getTodayStartTimeStr() {
        return getDateTimeStr(getTodayStartTime(new Date()));
    }

    /**
     * 獲取指定日期的開始時間字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getTodayStartTimeStr(Date date) {
        return getDateTimeStr(getTodayStartTime(date));
    }

    /**
     * 獲取今天的結束時間字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getTodayEndTimeStr() {
        return getDateTimeStr(getTodayEndTime(new Date()));
    }

    /**
     * 獲取指定日期的結束時間字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getTodayEndTimeStr(Date date) {
        return getDateTimeStr(getTodayEndTime(date));
    }

    /**
     * 獲得指定日期所在日的開始時間字符串
     *
     * @param date 指定日期
     * @return String 例如:2020-12-06 00:00:00
     */
    public static String getDateStartTimeStr(Date date) {
        String result = format(date, DATE_PATTERN);
        return result.concat(" ").concat(START_TIME);
    }

    /**
     * 獲得指定日期所在日的結束時間字符串
     *
     * @param date 指定日期
     * @return String 例如:2020-12-06 23:59:59
     */
    public static String getDateEndTimeStr(Date date) {
        String result = format(date, DATE_PATTERN);
        return result.concat(" ").concat(END_TIME);
    }

    /**
     * 根據日歷返回日期時間字符串
     *
     * @param calendar 日歷
     * @return String 日期時間字符串
     */
    public static String getDateTimeStr(Calendar calendar) {
        StringBuffer buf = new StringBuffer("");

        buf.append(calendar.get(Calendar.YEAR));
        buf.append("-");
        buf.append(calendar.get(Calendar.MONTH) + 1 > 9 ? calendar.get(Calendar.MONTH) + 1 + ""
                : "0" + (calendar.get(Calendar.MONTH) + 1));
        buf.append("-");
        buf.append(calendar.get(Calendar.DAY_OF_MONTH) > 9 ? calendar.get(Calendar.DAY_OF_MONTH) + ""
                : "0" + calendar.get(Calendar.DAY_OF_MONTH));
        buf.append(" ");
        buf.append(calendar.get(Calendar.HOUR_OF_DAY) > 9 ? calendar.get(Calendar.HOUR_OF_DAY) + ""
                : "0" + calendar.get(Calendar.HOUR_OF_DAY));
        buf.append(":");
        buf.append(calendar.get(Calendar.MINUTE) > 9 ? calendar.get(Calendar.MINUTE) + ""
                : "0" + calendar.get(Calendar.MINUTE));
        buf.append(":");
        buf.append(calendar.get(Calendar.SECOND) > 9 ? calendar.get(Calendar.SECOND) + ""
                : "0" + calendar.get(Calendar.SECOND));
        return buf.toString();
    }

    /**
     * 獲取今年的第一天
     *
     * @return Calendar 日歷
     */
    public static Calendar getStartDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar;
    }

    /**
     * 獲取今年的最后一天
     *
     * @return Calendar 日歷
     */
    public static Calendar getEndDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        int i = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
        calendar.set(Calendar.DAY_OF_YEAR, i);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar;
    }

    /**
     * 獲取本月的第一天
     *
     * @return Calendar 日歷
     */
    public static Calendar getStartDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar;
    }

    /**
     * 獲取本月的最后一天
     *
     * @return Calendar 日歷
     */
    public static Calendar getEndDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        int i = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(Calendar.DAY_OF_MONTH, i);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar;
    }

    /**
     * 獲取本周的第一天,一個星期的第一天是星期一,最后一天是星期天
     *
     * @return Calendar 日歷
     */
    public static Calendar getStartDayOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 設置一個星期的第一天,按中國的習慣一個星期的第一天是星期一
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar;
    }

    /**
     * 獲取本周的最后一天,一個星期的第一天是星期一,最后一天是星期天
     *
     * @return Calendar 日歷
     */
    public static Calendar getEndDayOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 設置一個星期的第一天,按中國的習慣一個星期的第一天是星期一
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);

        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar;
    }

    /**
     * 獲取今天開始時間
     *
     * @return
     */
    public static Calendar getTodayStartTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar;
    }

    /**
     * 獲取今天結束時間
     *
     * @return
     */
    public static Calendar getTodayEndTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar;
    }

    /**
     * 根據日期范圍,獲取按周期劃分的日期區間
     *
     * @param startDateStr 開始日期(格式:2020-11-29)
     * @param endDateStr   結束日期(格式:2020-12-02)
     * @param pattern      日期格式(支持:DATE_PATTERN,MONTH_PATTERN,YEAR_PATTERN)
     * @return List<String> 區間集合 例如:[2020-11-29,2020-11-30,2020-12-01,2020-12-02]
     */
    public static List<String> getDateStrList(String startDateStr, String endDateStr, String pattern) {
        Date start = parse(startDateStr, pattern);
        Date end = parse(endDateStr, pattern);
        return getDateStrList(start, end, pattern);
    }

    /**
     * 根據日期范圍,獲取按周期劃分的日期區間
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @param pattern   日期格式(支持:DATE_PATTERN,MONTH_PATTERN,YEAR_PATTERN)
     * @return List<String> 區間集合 例如:[2020-11-29,2020-11-30,2020-12-01,2020-12-02]
     */
    public static List<String> getDateStrList(Date startDate, Date endDate, String pattern) {
        List<String> result = new ArrayList<>();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        if (DATE_PATTERN.equals(pattern)) {
            while (startDate.before(endDate) || startDate.equals(endDate)) {
                result.add(new SimpleDateFormat(DATE_PATTERN).format(calendar.getTimeInMillis()));
                calendar.add(Calendar.DATE, 1);
                startDate = calendar.getTime();
            }
        } else if (MONTH_PATTERN.equals(pattern)) {
            while (startDate.before(endDate) || startDate.equals(endDate)) {
                result.add(new SimpleDateFormat(MONTH_PATTERN).format(calendar.getTimeInMillis()));
                calendar.add(Calendar.MONTH, 1);
                startDate = calendar.getTime();
            }
        } else if (YEAR_PATTERN.equals(pattern)) {
            while (startDate.before(endDate) || startDate.equals(endDate)) {
                result.add(new SimpleDateFormat(YEAR_PATTERN).format(calendar.getTimeInMillis()));
                calendar.add(Calendar.YEAR, 1);
                startDate = calendar.getTime();
            }
        }
        return result;
    }

    /**
     * 獲取當前日期前后num天的集合
     *
     * @param num 天數(正數:之后;負數:之前)
     * @return List<String> 前/后日期的集合(包含指定日期)
     */
    public static List<String> getDateStrList(int num) {
        return getDateStrList(new Date(), num, DATE_PATTERN);
    }

    /**
     * 獲取指定日期前后num天的集合
     *
     * @param date 指定日期
     * @param num  天數(正數:之后;負數:之前)
     * @return List<String> 前/后日期的集合(包含指定日期)
     */
    public static List<String> getDateStrList(Date date, int num) {
        return getDateStrList(date, num, DATE_PATTERN);
    }

    /**
     * 獲取指定日期前后num天的集合,帶日期格式參數
     *
     * @param date    指定日期
     * @param num     天數(正數:之后;負數:之前)
     * @param pattern 日期格式
     * @return List<String> 前/后日期的集合(包含指定日期)  例如:[2020-11-29,2020-11-30,2020-12-01]
     */
    public static List<String> getDateStrList(Date date, int num, String pattern) {
        List<String> result = new ArrayList<>();
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        boolean flag = false;
        if (num < 0) {
            num = Math.abs(num);
            flag = true;
        }
        for (int i = 0; i < num; i++) {
            result.add(new SimpleDateFormat(pattern).format(c.getTimeInMillis()));
            c.add(Calendar.DATE, flag ? -1 : 1);
        }
        if (flag) {
            Collections.reverse(result);
        }
        return result;
    }

    public static void main(String[] args) {
        System.out.println("=======================");
        System.out.println(getYearStr());
        System.out.println(getMonthStr());
        System.out.println(getDayStr());
        System.out.println(getHourStr());
        System.out.println(getMinuteStr());
        System.out.println(getSecondStr());

        System.out.println(getDateTimeStr());
        System.out.println(getDateStr());
        System.out.println(getTimeStr());
        System.out.println(getDayOfWeekStr());
        System.out.println(getDayOfWeekStr(parse("2020-12-05", DATE_PATTERN)));
        System.out.println(getDateTimeStr(System.currentTimeMillis(), DATETIME_PATTERN));

        System.out.println("=======================");
        System.out.println(parse("2020-12-31", DATE_PATTERN));

        System.out.println("=======================");
        System.out.println(addYears(1));
        System.out.println(addYears(new Date(), -1));
        System.out.println(addMonths(1));
        System.out.println(addMonths(new Date(), -1));
        System.out.println(addWeeks(1));
        System.out.println(addWeeks(new Date(), -1));
        System.out.println(addDays(1));
        System.out.println(addDays(new Date(), -1));
        System.out.println(addHours(1));
        System.out.println(addHours(new Date(), -1));
        System.out.println(addMinutes(1));
        System.out.println(addMinutes(new Date(), -1));
        System.out.println(addSeconds(1));
        System.out.println(addSeconds(new Date(), -1));
        System.out.println(addMilliSeconds(1));
        System.out.println(addMilliSeconds(new Date(), -1));

        System.out.println("=======================");
        System.out.println(getYearsBetween(parse("2020-01-30", DATE_PATTERN), parse("2021-01-29", DATE_PATTERN)));
        System.out.println(getMonthsBetween(parse("2020-01-30", DATE_PATTERN), parse("2021-01-29", DATE_PATTERN)));
        System.out.println(getWeeksBetween(parse("2020-01-30", DATE_PATTERN), parse("2020-02-06", DATE_PATTERN)));
        System.out.println(getDaysBetween(parse("2020-01-30", DATE_PATTERN), parse("2020-02-06", DATE_PATTERN)));
        System.out.println(getHoursBetween(parse("2020-01-30", DATE_PATTERN), parse("2020-02-06", DATE_PATTERN)));
        System.out.println(getMinutesBetween(parse("2020-01-30", DATE_PATTERN), parse("2020-02-06", DATE_PATTERN)));
        System.out.println(getSecondsBetween(parse("2020-12-06 19:47:00", DATETIME_PATTERN), parse("2020-12-06 19:47:50", DATETIME_PATTERN)));

        System.out.println("=======================");
        System.out.println(getCurrentSeason());

        System.out.println("=======================");
        System.out.println(getIntervalByDate(parse("2020-12-06 19:30:00", DATETIME_PATTERN)));
        System.out.println(getIntervalBySeconds(604800L));

        System.out.println("=======================");
        System.out.println(getCalendar(new Date()));
        System.out.println(getUTCTimeStr());

        System.out.println("=======================");
        System.out.println(timestampToStr(new Timestamp(System.currentTimeMillis())));

        System.out.println("=======================");
        System.out.println(compareNowDate("2020-12-07", DATE_PATTERN));
        System.out.println(compareDate(parse("2020-12-05", DATE_PATTERN), new Date()));
        System.out.println(compareDate("2020-12-05", "2020-12-06", DATE_PATTERN));

        System.out.println("=======================");
        System.out.println(isValidDate("2020-02-29 23:59:00"));
        System.out.println(isLastDayofMonth(parse("2020-11-01 00:00:00", DATETIME_PATTERN)));

        System.out.println("=======================");
        System.out.println(getYearStartTimeStr());
        System.out.println(getYearStartTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getYearEndTimeStr());
        System.out.println(getYearEndTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getMonthStartTimeStr());
        System.out.println(getMonthStartTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getMonthEndTimeStr());
        System.out.println(getMonthEndTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getWeekStartTimeStr());
        System.out.println(getWeekStartTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getWeekEndTimeStr());
        System.out.println(getWeekEndTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getTodayStartTimeStr());
        System.out.println(getTodayStartTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getTodayEndTimeStr());
        System.out.println(getTodayEndTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getDateStartTimeStr(parse("2020-11-01 00:00:00", DATETIME_PATTERN)));
        System.out.println(getDateEndTimeStr(parse("2020-11-01 00:00:00", DATETIME_PATTERN)));

        System.out.println("=======================");
        List<String> strList1 = getDateStrList(3);
        for (String s : strList1) {
            System.out.println(s);
        }

        System.out.println("=======================");
        List<String> dayList = getDateStrList(parse("2020-11-29", DATE_PATTERN), 3);
        for (String s : dayList) {
            System.out.println(s);
        }

        System.out.println("=======================");
        List<String> dateList = getDateStrList("2020-11-29", "2020-12-06", DATE_PATTERN);
        for (String s : dateList) {
            System.out.println(s);
        }

        System.out.println("=======================");
        List<String> strList = getDateStrList(parse("2020-11-29", DATE_PATTERN), parse("2020-12-06", DATE_PATTERN), DATE_PATTERN);
        for (String s : strList) {
            System.out.println(s);
        }
    }

}
作者:ThinkWon 發表于 2020/12/06 22:11:51 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/110779441
閱讀:1363 評論:8 查看評論
]]>
<![CDATA[[原]Java7日期時間API]]> http://www.gifted-edu.com/ThinkWon/article/details/110777654 http://www.gifted-edu.com/ThinkWon/article/details/110777654 ThinkWon 2020/12/06 22:02:56

作為開發者,經常需要處理日期時間。這里總結一下Java7常用的日期時間API。

Date

使用 java.util.Date 表示日期與時間,其承載了毫秒級精度的 Unix 時間。除此之外的功能(包括:承載 “年、月、日、時、分、秒” 字段,格式化,字符串解析),均標記為 @Deprecated

構造函數與常用方法

Date類支持兩個構造函數,如下表所示。

編號 構造函數 描述
1 Date() 此構造函數使用當前日期和時間來初始化對象。
2 Date(long millisec) 此構造函數接受一個參數,該參數等于自1970年1月1日午夜以來經過的毫秒數。

以下是Date類的方法列表

編號 方法 描述
1 boolean after(Date date) 如果調用Date對象包含的日期晚于date指定的日期,則返回true,否則返回false
2 boolean before(Date date) 如果調用Date對象包含的日期早于date指定的日期,則返回true,否則返回false
3 Object clone( ) 復制調用的Date對象。
4 int compareTo(Date date) 將調用對象的值與date的值進行比較。 如果值相等則返回0。 如果調用對象早于date,則返回負值。 如果調用對象晚于date,則返回正值。
5 int compareTo(Object obj) 如果obj對象是Date類對象,則與compareTo(Date)操作相同。 否則,它會拋出ClassCastException
6 boolean equals(Object date) 如果調用Date對象包含與date指定的時間和日期相同的時間和日期,則返回true,否則返回false
7 long getTime() 返回自1970年1月1日以來經過的毫秒數。
8 int hashCode() 返回調用對象的哈希碼。
9 void setTime(long time) 設置時間指定的時間和日期,表示從1970年1月1日午夜開始的經過時間(以毫秒為單位)。
10 String toString( ) 將調用Date對象轉換為字符串并返回結果。
11 static Date from(Instant instant) Instant對象獲取一個Date的實例。jdk1.8新增
12 Instant toInstant() 將此Date對象轉換為Instant 。jdk1.8新增

日期比較

Java使用以下三種方法來比較兩個日期:

  • 使用 getTime() 方法獲取兩個日期(自1970年1月1日經歷的毫秒數值),然后比較這兩個值。
  • 使用方法 before(),after() 和 equals()。例如,一個月的12號比18號早,則 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回true。
  • 使用 compareTo() 方法,它是由 Comparable 接口定義的,Date 類實現了這個接口。

測試Date構造方法和常用方法

/**
 * 測試Date構造方法和常用方法
 */
@Test
public void testDate() {
    // 參數表示1970-01-01 00:00:00到指定時間的毫秒數
    // Sat Dec 05 12:49:59 CST 2020
    Date date1 = new Date(1607143799610L);
    System.out.println(date1);
    // 當前時間
    Date date2 = new Date();
    System.out.println(date2);

    // date1是否date2之后
    System.out.println(date1.after(date2));
    // date1和date2是否相等
    System.out.println(date1.equals(date2));
    // 返回自1970年1月1日以來經過的毫秒數
    System.out.println(date2.getTime());
}

輸出結果

Sat Dec 05 12:49:59 CST 2020
Sat Dec 05 17:39:23 CST 2020
false
false
1607161163418

SimpleDateFormat

DateFormat是抽象類,能夠快速地進行日期與時間的格式化輸出和字符串解析,它與以語言無關的方式格式化并解析日期或時間,所以使用其子類SimpleDateFormat實現日期和字符串的相互轉換。

使用SimpleDateFormat測試日期和字符串的相互轉換

/**
 * 使用SimpleDateFormat測試日期和字符串的相互轉換
 *
 * @throws ParseException
 */
@Test
public void testSimpleDateFormat() throws ParseException {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // 將字符串轉化為日期
    Date date = sdf.parse("2020-12-05 16:31:39");
    System.out.println(date);

    // 將日期轉化為字符串
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    String str = dateFormat.format(date);
    System.out.println(str);
}

輸出結果

Sat Dec 05 16:31:39 CST 2020
2020/12/05 16:31:39

DateFormat格式代碼

要指定時間格式,請使用時間模式字符串。 在此模式中,所有ASCII字母都保留為模式字母,其定義如下

編號 字符 描述 示例
1 G 時代指示符 AD
2 y 四位數的年份值 2019
3 M 月份 July or 07
4 d 10
5 h 小時 A.M./P.M. (1~12) 12
6 H 24小時制的小時表示 (0~23) 22
7 m 分鐘 30
8 s 秒鐘 55
9 S 毫秒 234
10 E 星期幾 Tuesday
11 D 一年中的第幾天 360
12 F 一個月中的某一天 2 (second Wed. in July)
13 w 一年中的第幾個星期 40
14 W 一月中的第幾個星期 1
15 a A.M./P.M. 標記 PM
16 k 小時 (1~24) 24
17 K 小時 A.M./P.M. (0~11) 10
18 z 時區 Eastern Standard Time
19 轉義文本 Delimiter
20 " 單引號 `

Calendar

相比較于 java.util.Datejava.util.Calendar 除了承載毫秒級的 Unix 時間,還承載了時區信息(默認使用系統的時區),并且,提供了諸多接口:“年、月、日、時、分、秒” 字段的獲取與設置,時區設置,日期與時間的偏移調整。

從JDK1.1版本開始,在處理日期和時間時,系統推薦使用Calendar類進行實現。在設計上,Calendar類的功能要比Date類強大很多,而且在實現方式上也比Date類要復雜一些

Calendar類是一個抽象類,在實際使用時實現特定的子類的對象,創建對象的過程對程序員來說是透明的,只需要使用getInstance方法創建即可。

創建一個代表系統當前日期的Calendar對象

// 默認是當前日期
Calendar c = Calendar.getInstance();

創建一個指定日期的Calendar對象

使用Calendar類代表特定的時間,需要首先創建一個Calendar的對象,然后再設定該對象中的年月日參數來完成。

// 創建一個代表2020年6月12日的Calendar對象
Calendar c1 = Calendar.getInstance();
c1.set(2020, 6 - 1, 12);

Calendar類對象字段類型

Calendar類中用以下這些常量表示不同的意義,jdk內的很多類其實都是采用的這種思想

序號 常量 描述
1 Calendar.YEAR 年份
2 Calendar.MONTH 月份
3 Calendar.DATE 日期
4 Calendar.DAY_OF_MONTH 日期,和上面的字段意義完全相同
5 Calendar.HOUR 12小時制的小時
6 Calendar.HOUR_OF_DAY 24小時制的小時
7 Calendar.MINUTE 分鐘
8 Calendar.SECOND
9 Calendar.DAY_OF_WEEK 星期幾

Calendar類對象信息的設置

set設置

Calendar c1 = Calendar.getInstance();
// 把Calendar對象c1的年月日分別設這為:2020、6、12
public final void set(int year,int month,int date)
c1.set(2020, 6-1, 12);

add設置

把c1對象的日期加上10,也就是c1也就表示為10天后的日期,其它所有的數值會被重新計算

Calendar c1 = Calendar.getInstance();
c1.add(Calendar.DATE, 10);

其他字段屬性的add的意義以此類推

測試Calendar類對象信息的獲得,創建一個指定日期的Calendar對象

測試Calendar類對象信息的獲得,創建一個指定日期的Calendar對象

/**
 * 測試Calendar類對象信息的獲得,創建一個指定日期的Calendar對象
 */
@Test
public void testCalendar() {
    Calendar c1 = Calendar.getInstance();
    // 獲得年份
    int year = c1.get(Calendar.YEAR);
    // 獲得月份
    int month = c1.get(Calendar.MONTH) + 1;
    // 獲得日期
    int date = c1.get(Calendar.DATE);
    // 獲得小時
    int hour = c1.get(Calendar.HOUR_OF_DAY);
    // 獲得分鐘
    int minute = c1.get(Calendar.MINUTE);
    // 獲得秒
    int second = c1.get(Calendar.SECOND);
    // 獲得星期幾(注意(這個與Date類是不同的):1代表星期日、2代表星期1、3代表星期二,以此類推)
    int day = c1.get(Calendar.DAY_OF_WEEK);
    System.out.println("星期" + day + " " + year + "-" + month + "-" + date + " " + hour + ":" + minute + ":" + second);

    // 創建一個指定日期的Calendar對象
    Calendar c2 = Calendar.getInstance();
    c2.set(2020, (12 - 1), 5);
    System.out.println(c2.get(Calendar.YEAR) + "年" + (c2.get(Calendar.MONTH) + 1) + "月" + c2.get(Calendar.DATE) + "日");
}

輸出結果

星期7 2020-12-5 17:42:47
2020年12月5日

GregorianCalendar

GregorianCalendar是Calendar類的子類,并提供世界上大多數國家/地區使用的標準日歷系統。GregorianCalendar定義了兩個字段:AD和BC。這是代表公歷定義的兩個時代。

構造函數與常用方法

下面列出GregorianCalendar對象的幾個構造方法:

序號 構造函數 說明
1 GregorianCalendar() 在具有默認語言環境的默認時區內使用當前時間構造一個默認的 GregorianCalendar。
2 GregorianCalendar(int year, int month, int date) 在具有默認語言環境的默認時區內構造一個帶有給定日期設置的 GregorianCalendar
3 GregorianCalendar(int year, int month, int date, int hour, int minute) 為具有默認語言環境的默認時區構造一個具有給定日期和時間設置的 GregorianCalendar。
4 GregorianCalendar(int year, int month, int date, int hour, int minute, int second) 為具有默認語言環境的默認時區構造一個具有給定日期和時間設置的 GregorianCalendar。
5 GregorianCalendar(Locale aLocale) 在具有給定語言環境的默認時區內構造一個基于當前時間的 GregorianCalendar。
6 GregorianCalendar(TimeZone zone) 在具有默認語言環境的給定時區內構造一個基于當前時間的 GregorianCalendar。
7 GregorianCalendar(TimeZone zone, Locale aLocale) 在具有給定語言環境的給定時區內構造一個基于當前時間的 GregorianCalendar。

這里是GregorianCalendar 類提供的一些有用的方法列表:

序號 方法 說明
1 void add(int field, int amount) 根據日歷規則,將指定的(有符號的)時間量添加到給定的日歷字段中。
2 protected void computeFields() 轉換UTC毫秒值為時間域值
3 protected void computeTime() 覆蓋Calendar ,轉換時間域值為UTC毫秒值
4 boolean equals(Object obj) 比較此 GregorianCalendar 與指定的 Object。
5 int get(int field) 獲取指定字段的時間值
6 int getActualMaximum(int field) 返回當前日期,給定字段的最大值
7 int getActualMinimum(int field) 返回當前日期,給定字段的最小值
8 int getGreatestMinimum(int field) 返回此 GregorianCalendar 實例給定日歷字段的最高的最小值。
9 Date getGregorianChange() 獲得格里高利歷的更改日期。
10 int getLeastMaximum(int field) 返回此 GregorianCalendar 實例給定日歷字段的最低的最大值
11 int getMaximum(int field) 返回此 GregorianCalendar 實例的給定日歷字段的最大值。
12 Date getTime() 獲取日歷當前時間。
13 long getTimeInMillis() 獲取用長整型表示的日歷的當前時間
14 TimeZone getTimeZone() 獲取時區。
15 int getMinimum(int field) 返回給定字段的最小值。
16 int hashCode() 重寫hashCode.
17 boolean isLeapYear(int year) 確定給定的年份是否為閏年。
18 void roll(int field, boolean up) 在給定的時間字段上添加或減去(上/下)單個時間單元,不更改更大的字段。
19 void set(int field, int value) 用給定的值設置時間字段。
20 void set(int year, int month, int date) 設置年、月、日的值。
21 void set(int year, int month, int date, int hour, int minute) 設置年、月、日、小時、分鐘的值。
22 void set(int year, int month, int date, int hour, int minute, int second) 設置年、月、日、小時、分鐘、秒的值。
23 void setGregorianChange(Date date) 設置 GregorianCalendar 的更改日期。
24 void setTime(Date date) 用給定的日期設置Calendar的當前時間。
25 void setTimeInMillis(long millis) 用給定的long型毫秒數設置Calendar的當前時間。
26 void setTimeZone(TimeZone value) 用給定時區值設置當前時區。
27 String toString() 返回代表日歷的字符串。

測試GregorianCalendar構造方法和常用方法

/**
 * 測試GregorianCalendar構造方法和常用方法
 */
@Test
public void testGregorianCalendar() {
    String months[] = {
        "Jan", "Feb", "Mar", "Apr",
        "May", "Jun", "Jul", "Aug",
        "Sep", "Oct", "Nov", "Dec"};

    int year;
    // 初始化 Gregorian 日歷
    // 使用當前時間和日期
    // 默認為本地時間和時區
    GregorianCalendar gcalendar = new GregorianCalendar();
    // 顯示當前時間和日期的信息
    System.out.print("Date: ");
    System.out.print(months[gcalendar.get(Calendar.MONTH)]);
    System.out.print(" " + gcalendar.get(Calendar.DATE) + " ");
    System.out.println(year = gcalendar.get(Calendar.YEAR));
    System.out.print("Time: ");
    System.out.print(gcalendar.get(Calendar.HOUR_OF_DAY) + ":");
    System.out.print(gcalendar.get(Calendar.MINUTE) + ":");
    System.out.println(gcalendar.get(Calendar.SECOND));

    // 測試當前年份是否為閏年
    if (gcalendar.isLeapYear(year)) {
        System.out.println("當前年份是閏年");
    } else {
        System.out.println("當前年份不是閏年");
    }
}

輸出結果

Date: Dec 5 2020
Time: 17:33:12
當前年份是閏年

Timestamp

java.sql.Timestamp繼承java.util.Date,表示1970年1月1日午夜以來經過的毫秒數時間戳。可以精度達到納秒級,保留SQL TIMESTAMP小數秒值的功能,時間戳還提供格式化和解析操作,以支持時間戳值的JDBC轉義語法。

構造方法

編號 構造方法 描述
1 Timestamp(long time) 構造一個 Timestamp 對象,使用毫秒時間值。

常用方法

編號 方法 描述
1 boolean after(Timestamp ts) 判斷此 Timestamp 對象是否晚于給定的 Timestamp 對象。
2 boolean before(Timestamp ts) 判斷此 Timestamp 對象是否早于給定的 Timestamp 對象。
3 long getTime() 返回此 Timestamp 對象所表示的 00:00:00 GMT 以來 1970 年 1 月 1 日的毫秒數。
4 String toString() 設置 JDBC 時間戳轉義格式的時間戳的格式。
5 Instant toInstant() 將此 Timestamp 對象轉換為 Instant
6 LocalDateTime toLocalDateTime() 將此 Timestamp 對象轉換為 LocalDateTime

在 Java 8 之前,我們使用 java.sql.Timestamp 來表示時間戳對象,可以通過以下方式創建與獲取對象:

@Test
public void testTimestamp() {
    // 利用系統標準時間創建
    Timestamp timestamp = new Timestamp(System.currentTimeMillis());
    // 獲取自 1970-01-01 00:00:00 GMT 以來的毫秒數
    System.out.println(timestamp.getTime());

    // 從 Date 對象中創建
    Timestamp timestamp1 = new Timestamp((new Date()).getTime());
    System.out.println(timestamp1.toString());
}

輸出結果

1607750356429
2020-12-12 13:19:16.429
作者:ThinkWon 發表于 2020/12/06 22:02:56 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/110777654
閱讀:566
]]>
<![CDATA[[原]Quartz簡介]]> http://www.gifted-edu.com/ThinkWon/article/details/109936696 http://www.gifted-edu.com/ThinkWon/article/details/109936696 ThinkWon 2020/11/22 12:38:15



最近做了一個活動管理的項目,項目中有活動開始通知和活動結束通知等功能,需要創建大量的定時任務,最后選擇使用 Quartz 分布式調度框架。本文主要是對 Quartz 進行簡單介紹,了解 Quartz 是什么,有哪些核心元素,使用場景和特點等。

Quartz 是什么

What is the Quartz Job Scheduling Library?

Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components that may execute virtually anything you may program them to do. The Quartz Scheduler includes many enterprise-class features, such as support for JTA transactions and clustering.

Quartz is freely usable, licensed under the Apache 2.0 license.

Quartz Job Scheduling Library是什么? Quartz是功能強大的開源作業調度庫,幾乎可以集成到任何Java應用程序中-從最小的獨立應用程序到最大的電子商務系統。 Quartz可用于創建簡單或復雜的計劃,以執行數以十計,百計,萬計的工作。任務標準Java組件的任務,都可以執行您對其執行的任何編程操作。Quartz Scheduler包含許多企業級功能,例如對JTA事務和集群的支持。

Quartz是免費使用的,并根據Apache 2.0許可獲得許可。

Quartz 是 OpenSymphony 開源組織在任務調度領域的一個開源項目,完全基于 Java 實現。該項目于 2009 年被 Terracotta 收購,目前是 Terracotta 旗下的一個項目。官網地址:http://www.quartz-scheduler.org/

使用場景

  • 持久性任務 - 就是保持調度定時的狀態;
  • 任務管理 - 對調度任務進行有效的管理;

當遇到以下問題時:

  • 自動關閉30分鐘未支付的訂單
  • 與第三方公司對賬業務
  • 數據統計,比如博客系統統計日粉絲數,日閱讀量等
  • 活動開始和結束通知;
  • 想在每月25號,自動還款;
  • 每周或者每月的提醒事項,比如周總結或者月總結;

像這種某個時間點執行任務,或者每隔一段時間重復執行任務,都可以用Quartz實現

特點

  • 強大的調度功能,例如豐富多樣的調度方法,可以滿足各種常規和特殊需求;
  • 靈活的應用方式,例如支持任務調度和任務的多種組合,支持調度數據的多種存儲方式(DB,RAM等);
  • 支持分布式集群,在被Terracotta收購之后,在原來基礎上進行了進一步的改造。

Quartz 使用的設計模式

  • Builder模式
  • 組件模式
  • Factory模式

Java 語言實現定時任務的幾種方式

  • java.util.Timer:一個 JDK 中自帶的處理簡單定時任務的工具。
  • java.util.concurrent.ScheduledExecutorService:JDK 中的定時任務接口,可以將定時任務與線程池功能結合使用。
  • org.springframework.scheduling.annotation.Scheduled:Spring 框架中基于注解來實現定時任務處理。
  • Quartz:一個完全由 Java 語言編寫的,支持分布式調度任務的開源框架。

核心元素

Quartz任務調度的核心元素主要有:Scheduler任務調度器、Trigger觸發器、Job任務、JobDetail調度程序。其中trigger和job、jobDetail為任務調度的元數據,而Scheduler為實際執行調度的控制器。

Scheduler

任務調度器,一個調度容器中可以注冊多個JobDetail和Trigger。當Trigger與JobDetail組合,就可以被Scheduler容器調度了。正常情況下一個應用只需要一個Scheduler對象。

Scheduler 由 SchedulerFactory 創建:DirectSchedulerFactory或者StdSchedulerFactory。第二種工廠StdSchedulerFactory使用較多,因為DirectSchedulerFactory使用起來不夠方便,需要作許多詳細的手工編碼設置。Scheduler主要有三種:RemoteMBeanScheduler,RemoteScheduler和StdScheduler。

Trigger

觸發器,調度任務的時間規則。Quartz中主要提供了四種類型的Trigger:SimpleTrigger,CronTirgger,DateIntervalTrigger,和NthIncludedDayTrigger。這四種trigger可以滿足企業應用中的絕大部分需求。

Calendar

一些日歷特定時間點的集合。一個trigger可以包含多個Calendar,以便排除或包含某些時間點。

JobDetail

JobDetail是一個具體的可執行的調度程序,Job是這個可執行調度程序所要執行的內容,另外JobDetail還包含了任務調度的方案和策略。

JobDetail綁定指定的Job,每次Scheduler調度執行一個Job的時候,首先會拿到對應的Job,然后創建該Job實例,再去執行Job中的execute()的內容,任務執行結束后,關聯的Job對象實例會被釋放,且會被JVM GC清除。

為什么設計成JobDetail + Job,不直接使用Job

JobDetail定義的是任務數據,而真正的執行邏輯是在Job中。
這是因為任務是有可能并發執行,如果Scheduler直接使用Job,就會存在對同一個Job實例并發訪問的問題。而 JobDetail 綁定 Job 方式,Sheduler每次執行,都會根據JobDetail創建一個新的Job實例,這樣就可以規避并發訪問的問題。

Job

任務,表示要執行的具體工作或者被調度的任務。我們的任務類實現該接口,重寫execute方法來定義任務的執行邏輯。主要有兩種類型的job:無狀態的(stateless)和有狀態的(stateful)。對于同一個trigger來說,有狀態的job不能被并行執行,只有上一次觸發的任務被執行完之后,才能觸發下一次執行。Job主要有兩種屬性:volatility和durability,其中volatility表示任務是否被持久化到數據庫存儲,而durability表示在沒有trigger關聯的時候任務是否被保留。兩者都是在值為true的時候任務被持久化或保留。一個job可以被多個trigger關聯,但是一個trigger只能關聯一個job。

JobExecutionContext

JobExecutionContext中包含了Quartz運行時的環境以及Job本身的詳細數據信息。

當Schedule調度執行一個Job的時候,就會將JobExecutionContext傳遞給該Job的execute()中,Job就可以通過JobExecutionContext對象獲取信息。

核心元素之間的關系

Quartz 類圖

主要線程

在Quartz中,有兩類線程,也即執行線程和調度線程,其中執行任務的線程通常用一個線程池維護。線程間關系如下圖
img
在quartz中,Scheduler調度線程主要有兩個:regular Scheduler Thread(執行常規調度)和Misfire Scheduler Thread(執行錯失的任務)。其中Regular Thread 輪詢Trigger,如果有將要觸發的Trigger,則從任務線程池中獲取一個空閑線程,然后執行與Trigger關聯的job;Misfire Thraed則是掃描所有的trigger,查看是否有錯失的,如果有的話,根據一定的策略進行處理。

數據存儲

Quartz中的trigger和job需要存儲下來才能被使用。Quartz中有兩種存儲方式:RAMJobStore,JobStoreSupport,其中RAMJobStore是將trigger和job存儲在內存中,而JobStoreSupport是基于jdbc將trigger和job存儲到數據庫中。RAMJobStore的存取速度非常快,但是由于其在系統被停止后所有的數據都會丟失,所以在集群應用中,必須使用JobStoreSupport。

注意:quartz集群是通過數據庫表來感知其他的應用的,各個節點之間并沒有直接的通信。只有使用持久的JobStore才能完成Quartz集群。

quartz的sql所在位置

1、/docs/dbTables

2、org/quartz/impl/jdbcjobstore

其中表結構

Serial Number Table Name Description
1 QRTZ_CALENDARS 存儲Quartz日歷信息
2 QRTZ_CRON_TRIGGERS 存放Cron類型的Trigger,包括Cron表達式和時區信息
3 QRTZ_FIRED_TRIGGERS 存儲與已觸發的Trigger相關的狀態信息,以及相聯Job的執行信息
4 QRTZ_PAUSED_TRIGGER_GRPS 存儲已暫停的Trigger組的信息
5 QRTZ_SCHEDULER_STATE 存儲少量的Scheduler相關的狀態信息
6 QRTZ_LOCKS 存儲程序的悲觀鎖的信息(如果使用了悲觀鎖)
7 QRTZ_JOB_DETAILS 存儲每一個已配置的JobDetail信息
8 QRTZ_SIMPLE_TRIGGERS 存儲Simple類型的Trigger,包括重復次數、間隔、以及已觸的次數
9 QRTZ_BLOG_TRIGGERS 以Blob類型存儲的Trigger
10 QRTZ_TRIGGERS 存儲已配置的Trigger的基本信息
11 QRTZ_TRIGGER_LISTENERS Trigger監聽器
12 QRTZ_JOB_LISTENERS Job監聽器

注意:cron方式需要用到的4張數據表: QRTZ_TRIGGERS,QRTZ_CRON_TRIGGERS,QRTZ_FIRED_TRIGGERS,QRTZ_JOB_DETAILS。

作者:ThinkWon 發表于 2020/11/22 12:38:15 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/109936696
閱讀:1475 評論:2 查看評論
]]>
<![CDATA[[原]富爸爸窮爸爸-讀書筆記]]> http://www.gifted-edu.com/ThinkWon/article/details/109261723 http://www.gifted-edu.com/ThinkWon/article/details/109261723 ThinkWon 2020/10/24 16:33:37

在這里插入圖片描述

概述

羅伯特·清崎(英文名:Robert Toru Kiyosaki),1947年4月8日生于美國夏威夷,日語名清崎徹(Kiyosaki Toru),第4代日裔美國人,《富爸爸,窮爸爸》系列書籍的主要作者。投資家、企業家、教育家。“富爸爸”系列叢書合著者,富爸爸公司合伙創始人,財商教育的領路人。

“富爸爸,窮爸爸”是一個很簡單的故事,是羅伯特·清崎講述的他自己年輕時的故事。

清崎有兩個爸爸:“窮爸爸”是他的親生父親,一個高學歷的教育官員;“富爸爸”是他好朋友的父親,一個高中沒畢業卻善于投資理財的企業家。清崎遵從“窮爸爸”為他設計的人生道路:上大學,服兵役,參加越戰,走過了平凡的人生初期。直到1977年,清崎親眼目睹一生辛勞的“窮爸爸”失了業,“富爸爸”則成了夏威夷的有錢人。清崎毅然追尋“富爸爸”的腳步,踏入商界,從此登上了致富快車。清崎以親身經歷的財富故事展示了“窮爸爸”和“富爸爸”截然不同的金錢觀和財富觀:窮人為錢工作,富人讓錢為自己工作!

“MBW”財商理論體系,即從創富動機、創富行為習慣、創富路徑三方面培養學員的財商

正如富爸爸在書中所說,世界變了,金錢游戲的規則也變了。對于讀者和創業者來說,也要應時而變,理解金錢的語言、學會金錢的游戲。只有這樣,你才能玩轉金錢游戲、實現財務自由。

大部分增長的收入都流向企業家及投資者,而并非勞動者——那些為錢而工作的人們。

序言 這就是你所需要的

他們勸告他們的孩子努力學習,取得好成績,然后找個安穩的工作或職業。而對于錢,除了從那些利用他們的天真而獲利的人那兒學到點東西之外,他們什么都沒學到。他們終生辛苦地工作,他們的下一代又將重復相同的過程,這就叫"老鼠賽跑"。

你給孩子的最危險的建議就是:去學校,好好念書,然后找個安穩的工作。只有精通會計和投資才能跳出“老鼠賽跑”的陷阱,可以說這是兩個最難掌握的專業。要記住,財商是在解決財務問題的過程中鍛煉出來的

第一部分 課程

第一章 富爸爸,窮爸爸

下面借用頭條@人生自由之路對富爸爸窮爸爸的總結

在這里插入圖片描述

第二章 富人不為錢工作

窮人和中產階級為錢工作,而富人不為錢工作

假如你學會了生活這門課程,做任何事情你都會游刃有余。

生活推著我們所有的人,有些人放棄了,有些人在抗爭。少數人學會了這門課程,取得了進步,他們歡迎生活來推動他們,對他們來說,這種推動意味著他們需要并愿意去學習一些東西。他們學習,然后取得進步。但大多數人放棄了,還有一部分人像你一樣在抗爭。

如果你是那種沒有勇氣的人,生活每次推動你,你都會選擇放棄。如果你是這種人,你的一生會過得穩穩當當,不做錯事、假想著有事情發生時自救,然后慢慢變老,在無聊中死去。你會有許多朋友,他們很喜歡你,因為你真的是一個努力工作的好人。你的一生過得很安穩,處世無誤。但事實是,你向生活屈服了,不敢承擔風險。你的確想贏,但失敗的恐懼超過了成功的興奮。只有你知道,在你內心深處,你始終認為你不可能贏,所以你選擇了穩定。

如果你不能下定決心,就永遠也學不會如何賺錢。機會總是轉瞬即逝。知道什么時候要迅速做出決定是一項非常重要的技能

生活中的很多事情是我們無法控制的。我學會了專注于我所能控制的:我自己。如果事情必須改變,首先要改變的就是我自己

人們的生活永遠被這兩種感覺所控制:恐懼和貪婪

正是出于恐懼的心理,人們才想找一份安穩的工作。大多數人都希望有一份工資收入,因為他們都有恐懼和貪婪之心。一開始,沒錢的恐懼會促使他們努力工作,得到報酬后,貪婪或欲望又讓他們想擁有所有用錢能買到的好東西。于是就形成了一種模式。

忠實于你的感情,以你喜歡的方式運用你的頭腦和感情,不要讓它們控制你。恐懼和欲望組成的陷阱,按照你們喜歡的方式利用恐懼和欲望,而不要讓它們控制你們。

不要因為害怕付不起賬單就起床去工作,希望以這種方法來解決問題。你要花時間去思考這個問題:更努力地工作是解決問題的最好方法嗎? 大多數人都害怕知道真相——他們被恐懼所支配——不敢去思考,就出門去找工作了。

第三章 為什么要教授財務知識

我想有太多人過多地關注錢,而不是關注他們最大的財富——所受的教育。只有知識才能解決問題并創造財富,那些不是靠財務知識掙來的錢也不會長久。

從長遠來看,重要的不是你掙了多少錢,而是你能留下多少錢,以及能夠留住多久。

規則:你必須明白資產和負債的區別,并且購買資產。 如果你想致富,這一點你必須知道。這就是第一條規則,也是唯一一條規則。

資產的現金流

在這里插入圖片描述

負債的現金流

在這里插入圖片描述

資產是能把錢放進你口袋里的東西。負債是把錢從你口袋里取走的東西

窮人的現金流

在這里插入圖片描述

中產階級的現金流

在這里插入圖片描述

在這里插入圖片描述

富人的現金流

在這里插入圖片描述

在這里插入圖片描述

當我還是孩子時,我的爸爸告訴我日本人注重3種力量:劍、寶石和鏡子。

劍象征著武器的力量。美國人在武器上已經花了上千億美元,是世界上的超級軍事大國。

寶石象征著金錢的力量。有句格言很有道理:記住黃金規則:有黃金的人制定規則。

鏡子象征著自知的力量。從日本的傳奇故事中我們得知,自知是 3 種力量中最寶貴的。當他們“照鏡子”時,才能發現真相,即大多數人熱衷于“穩定”是出于恐懼。

買房子,到底是買的資產還是負債?

在這里插入圖片描述

決定買很昂貴的房子,而不是早早開始證券投資,將對一個人的生活在以下 3個方面形成沖擊:

  1. 失去了用其他資產增值的時機。
  2. 本可以用來投資的資本將用于支付房子高額的維修和保養費用。
  3. 失去受教育的機會。

人們經常把他們的房子、儲蓄和退休金計劃作為他們資產項的全部內容。因為沒錢投資,也就不去投資,這就使他們無法獲得投資經驗,并永遠不會成為被投資界稱為“成熟投資者”的人。而最好的投資機會往往都是先給那些“成熟投資者”的,再由他們轉手給那些謹小慎微的投資者, 當然,在轉手時他們已經拿走了絕大部分的利益。

第四章 管住自己的事業

麥當勞是做什么的?

其實并不是做漢堡包的,真正的生意是房地產。在他商業計劃中,麥當勞的基本業務是出售麥當勞各個分店。他一向很重視每個分店的地理位置,因為他知道房產和位置將是每個分店獲得成功的最重要的因素。實際上,是那些買下分店的人在為麥當勞買下的土地支付費用。今天,麥當勞在美國以及世界其他地方都擁有一些位于街角和十字路口的黃金地段。擁有的房地產甚至比天主教會還多。

致富的第三個秘訣:“關注自己的事業。” 存在財務問題的人經常耗費一生為別人工作,其中許多人在他們不能工作時就變得一無所有。

你的職業是什么?你的事業又是什么?

你在哪里工作只是一份職業,真正擁有它才算是你的事業。比如你在銀行工作,但并不擁有銀行。從事你所學的專業的可怕后果在于,它會讓你忘記關注自己的事業。人們耗盡一生去關注別人的事業并使他人致富。

我們應該獲取什么樣的資產呢?

1.不需我到場就可以正常運作的業務。我擁有它們,但由別人經營和管理。如果我必須在那兒工作,那它就不是我的事業而是我的職業了; 2.股票; 3.債券; 4.共同基金; 5.能夠產生收入的房地產; 6.票據(借據); 7.版稅,如音樂、手稿、專利; 8.其他任何有價值、可產生收入或有增值潛力并且有很好銷路的東西。

只有你把額外的收入用來購買可產生收入的資產,你才能獲得真正的財務安全。

只有當你真的想擁有自己的公司時,我才建議你這么做。否則,你還是繼續上班并關注自己的事業吧。

真正的奢侈品是對投資和積累真正資產的獎勵。 大多數人則會沖動地用貸款去買新車或其他奢侈品,他們可能對生活有些厭煩了,所以期待有點新玩意兒。用貸款買奢侈品,結果遲早會讓人們放棄那些東西,因為借下的債是個沉重的負擔。

第五章 稅收的歷史和公司的力量

稅收的初衷是懲罰有錢人,而現實卻是它懲罰了對它投贊同票的中產階級和窮人。看起來稅收最終只是懲罰了窮人和中產階級自己,因為他們缺少財務知識。無論“劫富”的呼聲多高,富人總有辦法從中脫身,這就是稅收最終總會落到中產階級頭上的原因。

真正的資本家則利用他們的財務知識逃脫了。他們借助于公司的保護來避稅。公司的確可以保護富人。因為企業所得稅率低于個人收入所得稅率。此外,正如之前我們所討論過的,公司的某些支出可以用稅前收入支付。

最大的敵人不是老板或上司,而是稅負,稅負總想從你那里拿走更多,如果你不進行阻止。

財商是由4個方面的專門知識構成的:

1.會計

會計就是財務知識或解讀數字的能力。如果你想建立一個自己的商業帝國,財務知識是非常重要的。你管理的錢越多,就越要精確,否則這幢大廈就會倒塌。這需要左腦來處理,是細節的部分。財務知識能幫助你讀懂財務報表,還能讓你辨別一項生意的優勢和劣勢。

2.投資

投資是錢生錢的科學。投資涉及策略和方案,這要右腦來做,是屬于創造的部分。

3.了解市場

了解市場是供給與需求的科學。這要求了解受感情驅動的市場的“技術面”。市場的另一個因素是“基本面”,或者說是一項投資的經濟意義。一項投資究竟有無意義最終取決于當前的市場狀況。

4.法律

利用一個具有會計、投資和市場運營的企業會使你的財富實現爆炸性地增長。了解減稅優惠政策和公司法的人會比雇員和小業主更快致富。這就像一個人在走,而另一個人卻在飛,久而久之這種差距就更大了。

讓羅伯特這一切變為可能的是財商,或者叫財務知識。它由4部分組成:會計(財務知識,也就是解讀數字的能力以及評估一項生意的優勢和劣勢)、投資(錢生錢的科學和策略)、了解市場(供給與需求的科學以及市場條件)、法律(減稅優惠和在訴訟中獲得保護)。

第六章 富人的投資

在現實生活中,人們往往是依靠勇氣而不是智慧去取得領先的位置的。

為什么要去冒險?為什么必須永不停止地提高自己的財商?為什么必須懂得財務知識?就是為了獲得更多的選擇機會。

能從“老鼠賽跑”中最快勝出的人,都是對數字很精通而且具有創造性理財思維的人,他們懂得不同的理財選擇有不同的意義。

金錢不是真實的資產。我們唯一的,也是最重要的資產是我們的頭腦。 如果受到良好的訓練,它轉瞬間就能創造大量的財富。

那時候經濟很不景氣,而對于投資者來說,這卻是一個絕好的市場良機。我把一大筆錢投資于股票和房地產市場,所以手頭缺少現金。每個人都在賣出,而我在買入。我不是在省錢,而是在投資。我妻子和我把 100多萬美元的現金投在了必將迅速上升的市場里,我們相信這是最好的投資機會。市場不景氣,我一定不能錯過任何一次細小的投資機會。原來價值 10萬美元的房子現在只值 7. 5萬美元。

如果你清楚自己在做什么,就不是在賭博;如果你把錢投進一筆交易然后只是祈禱,才是在賭博。在任何一項投資中,成功的辦法都是運用你的技術知識、智慧以及對于這個游戲的熱愛來減少意外、降低風險

好機會是用你的腦子而不是用你的眼睛看到的。 大部分人無法致富僅僅是因為他們沒有受到理財訓練,因而不知道機會其實就在眼前。

要想成為理財能手,你就必須具備 3 種技能。風險無處不在,要學會駕馭風險,別總想回避風險。

1.如何尋找其他人都忽視的機會。

2.如何增加資金。你知道的比你買到的更重要。投資不僅僅是買東西,而應該是一個不斷學習的過程。

3.怎樣把精明的人組織起來。

第七章 學會不為錢工作

對于受過良好教育的爸爸來說,工作的穩定就是一切;而對于富爸爸來說,不斷學習才是一切

如果要破產的話,一定要在30歲以前,他的建議是“這樣你還有時間東山再起”。

勸告年輕人在找工作時要看能從中學到什么,而不是只看能掙多少錢。在選擇某種職業或陷入“老鼠賽跑”的陷阱之前,要仔細看看腳下的路,弄清楚自己到底想獲得什么技能。

我承認為了金錢和生活安穩而工作是很重要,但我仍主張要再找一份工作,以便從中學到另一種技能。我常常提議,如果想學習銷售技能,最好進一家網絡營銷公司,也被稱為多級營銷公司。這類公司多半能夠提供良好的培訓項目,幫助人們克服因失敗造成的沮喪和恐懼心理,這種心理往往是導致人們不成功的主要原因。從長遠來看,教育比金錢更有價值。

麥當勞擁有一套出色的商業體系。許多才華橫溢的人之所以貧窮,就是因為他們只是專心于做好產品,而對商業體系卻知之甚少。

成功所必需的管理技能包括:

1.對現金流的管理。

2.對系統(包括你本人、時間及家庭)的管理。

3.對人員的管理。

最重要的專業技能是銷售技能和營銷技能。溝通能力,如書面表達、口頭表達及談判能力等對一個人的成功來說更是至關重要。

第二部分 開端

第八章 克服困難

掌握財務知識的人有時候還是不能積累豐厚的資產項,其主要原因有 5個:

1.恐懼心理。對可能虧錢的恐懼心理,要知道不喜歡失敗和害怕失敗之間有著巨大的差別,大部分人因為害怕失敗而失敗。

對于超過 70%的人來說,這可能還算是一個較好的投資組合。畢竟,一個安全的投資組合總比什么都沒有強得多。一個安全的投資組合對于注重安全的人來說是很合適的,但是,安全地、平衡地投資于一個投資組合,卻不是一個成功的投資者應有的投資方式。如果你的資金很少而又想致富,你必須首先集中于一點,而不是追求平衡。 那些成功的投資者,在最初肯定不是追求平衡的,追求平衡的人只會在原地踏步。要進步,你必須先做到不平衡,并注意怎樣才能使自己不斷進步。

如果你有致富的愿望,就必須集中精力。把你大部分的雞蛋放在較少的籃子里,別像窮人和中產階級那樣:把很少的雞蛋放在許多籃子里。

2.憤世嫉俗。 大部分人之所以貧窮,是因為在他們想要投資的時候,周圍到處是跑來跑去的“小雞”,叫嚷著“天要塌下來了,天要塌下來了”。“小雞”們的說法很有影響力,因為我們每個人的心中也都有一只“小雞”。

未經證實的懷疑和恐懼會使人們成為憤世嫉俗者。憤世者抱怨現實,而成功者分析現實。

3.懶惰。忙碌的人常常是最懶惰的人。那么,怎么才能治療這種惰性呢?答案就是要“貪婪”一點。

富爸爸并不關心我們想買什么,他只想通過促使我們不斷思索“我怎樣才能付得起”來創造一種更強有力的思想和更有活力的精神。

埃莉諾.羅斯福說的最好:“做你內心認為正確的事情因為你不管怎么做總會受到批評。如果你做,會受到指責;而你不做,還是會受到指責。”

4.不良習慣。如果我也學會先支付給自己,就會在財務上更‘強壯’,噢,應該是在精神上和財務上都更加‘強壯’。

5.自負、傲慢。傲慢是自大和無知的結合體。“我知道的東西給我帶來金錢,我不知道的東西使我失去金錢。因為每當我自高自大時,我就認為我不知道的東西并不重要。”

如果你知道自己在某一問題上有所欠缺,你就應該找一位本領域的專家或是一本相關的書,馬上開始教育自己。

第三部分 開始行動

第九章 開始行動

10個步驟來開發上帝賜予你的才能,這種才能只有你才可以控制:

1.我需要一個超現實的理由——精神的力量。沒有強有力的理由和目標,任何事都會變得非常困難。

2.每天作出自己的選擇——選擇的力量。阻礙人們去思考這樣兩件事情:第一是時間,這是你最珍貴的資產;第二是學習,正因為你沒有錢,就更要去學習。

首先投資于教育。實際上,你所擁有的唯一真正的資產就是你的頭腦,這是我們能控制的最強有力的工具。就像我剛才說的人們都有選擇的力量,當我們逐漸長大時,每個人都要選擇要學習什么樣的知識。你可以整天看音樂電視,也可以閱讀高爾夫球雜志、上陶藝班或是理財規劃培訓班,你可以進行選擇。在投資方面,大部分人選擇的是直接去投資,而不是首先投資于學習如何投資。

3.慎重地選擇朋友——關系的力量。在積累財富的過程中,最困難的事情莫過于堅持自己的選擇而不盲目從眾。

明智的投資者往往會購買一項不被大眾看好的投資,他們懂得利潤在購買時就已確定,而不是在出售時獲得的,他們會耐心地等待投資的增值。

你越早得到信息,獲利的機會就越大,風險也會越小,這就是朋友的作用。

4.掌握一種模式,然后再學習一種新的模式——快速學習的力量。

5.首先支付自己——自律的力量。如果你控制不了自己,就別想著致富。生活推著你轉。生活之所以能推著你轉,不是因為生活的力量很強大,而是因為你缺乏自律。

有膽量不隨大流才能致富。你也許并不軟弱,但一旦涉及金錢,往往會變得怯懦。

窮人有一些不好的習慣,其中一個普遍的壞習慣就是隨便動用儲蓄。富人知道儲蓄只能用于創造更多的收入,而不是用來支付賬單。

生活應當是快樂的,如果你喚醒自己的理財天賦,就有機會擁有人生中最美好的東西:致富,并不以犧牲舒適為代價地支付賬單。這就是財商。

開創事業所必備的最重要的3種管理技能是:

  • 現金流管理。

  • 人事管理。

  • 個人時間管理。

6.給你的經紀人以優厚的報酬——好建議的力量。

記住那句古老的格言:“如果你需要一本百科全書,千萬別找百科全書推銷員。”

7.做一個“印第安給予者”——無私的力量。

因此明智的投資者不只看到投資回報率,而且還能看到,一旦收回投資,就能額外得到的資產。這也是財商。

8.用資產來購買奢侈品——專注的力量。 我習慣于用消費的欲望來激發并利用我的理財天賦去投資。

輕松的道路往往會越走越艱難,而艱難的道路往往會越走越輕松。

要成為金錢的主人,你就要比金錢更精明。然后金錢才能按照你的要求辦事,它會屈服于你,這樣你就是它的主人,而不是它的奴隸。這就是財商。

9.對英雄的崇拜——神話的力量。

在投資問題上,許多人總是說有多么多么困難,而不去找能夠“幫助”他們的英雄。

10.先予后取——給予的力量。

一個人抱著柴火坐在寒冷的夜里,沖著一只大火爐叫道:“你什么時候給我溫暖,我就什么時候給你添柴火。”推而廣之,當涉及金錢、愛情、幸福、銷售和合約等時,都應記住要為自己想要的東西先付出,然后才能得到加倍的回報。

慷慨一些。反過來,那些人也會慷慨地對你。

第十章 還想要更多的嗎?這里有一些要做的事情

做同一件事情卻希望有不同的結果是神志不清的表現。不要做那些無效的事情,找一些有效的事情去做。

那些介紹各種“模式”的書。你能學到那些你以前不知道的模式。花時間來讀書,然后采取行動,然后找相關的人交流,然后找到相關的買賣。

你必須到市場上去和許多人談,做許多報價、還價、談判、拒絕或者接受。從尋找、報價、拒絕、談判到成交,幾乎是人的一生中要經歷的全部過程。

行動的人總會擊敗不行動的人。最重要的是“做過”和“去做”。

結束語 怎樣用7000美元支付孩子的大學費用

變富有的關鍵是擁有盡快將勞動性收入轉換成被動收入或投資組合收入的能力。

在會計領域,有三種收入:勞動性收入、投資組合收入和被動收入。在大多數情況下,被動收入多來自房地產投資,投資組合收入一般來自股票和債券等紙質資產投資。

只有工作才能賺錢的思想是在理財上不成熟的人才有的。

上天賜予我們每個人兩樣偉大的禮物:思想和時間。你可以運用這兩件禮物去做你愿意做的事情。每一美元鈔票到了你的手中,你,且只有你,才有權決定自己的前途。愚蠢地用掉它,你就選擇了貧困;把錢用在負債項上,你就會成為中產階級;投資于你的頭腦,學習如何獲取資產,富有將成為你的目標和你的未來。選擇只能由你作出。每一天,面對每一美元,你都在作出自己是成為一個富人、窮人還是中產階級的抉擇。

作者:ThinkWon 發表于 2020/10/24 16:33:37 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/109261723
閱讀:2857 評論:13 查看評論
]]>
<![CDATA[[原]高效能人士的七個習慣-讀書筆記]]> http://www.gifted-edu.com/ThinkWon/article/details/108941111 http://www.gifted-edu.com/ThinkWon/article/details/108941111 ThinkWon 2020/10/06 17:09:03


在這里插入圖片描述

概述

《高效能人士的七個習慣》入選《福布斯》“有史以來最具影響力的10大管理類圖書之一”,“20世紀有影響力的商業書籍”;是中國商界最經典、最著名的一部培訓教材;自1989年出版以來,高居《紐約時報》、《華爾街日報》、新華書店等暢銷書榜長達25年

作者史蒂芬?柯維。他是美國學界的“思想巨匠”,《經濟學人》雜志推舉其為“最具前瞻性的管理思想家”。在美國乃至全世界,史蒂芬?柯維的思想成就與戴爾?卡耐基、拿破侖?希爾并肩比齊。

由內而外全面造就自己

1、要改變現狀,首先要改變自己;要改變自己,先要改變我們對問題的看法

2、品格比技巧更重要。技巧與品格比,雖然可以很高效地讓別人為你賣力,但是一旦人家發現你品格有問題,就會把你所有的言不由衷當做虛偽,會失去所有。

3、思維定式即是指我們“看”世界的方法,這種“看”和視覺無關,主要指我們的感知、理解與詮釋。它是每個人看待世界的方式,未必與現實相符。你覺得整個世界都是善意的,那么整個世界就會對你釋放善意,你覺得你是成功的,你會發現所有的事情都在證明這一點,就是自證預言。我們對事物的看法決定著我們的思想與行為

4、思維轉換的力量,就是給腦子洗澡,讓認知升級。不論思維轉換的結果是否積極,過程是否漸進,思維方式的改變會讓我們的世界觀發生改變,而且改變的力度驚人。原則是人類行為的指南針,歷經考驗,長盛不衰,不證自明。這些正確的思維方式,堅守的“原則”就是人類歷史上顛撲不滅的真理,即是燈塔。

效能的定義

效能的兩個要素

金鵝與金蛋的預言,說明真正的效能應該包含兩個要素:一是“產出”,即金蛋;二是“產能”——生產的資產或能力,即下金蛋的鵝。維護產能可以保證持續產出,也就是磨刀不誤砍柴工。

三類資產

資產可以分為物質資產、金融資產以及人力資產三大類,金融資產的本金就是產能,要想獲得更多的產出,必須投入更多的本金。人力資產,和睦親密的夫妻關系是產出,那么對彼此的關注和照顧就是產能。

習慣的定義

習慣對我們的生活有極大的影響,因為它是一貫的,在不知不覺中,經年累月影響著我們的品德,暴露出我們的本性,左右著我們的成敗。

亞里士多德也曾經說過:人的行為總是一再重復。因此卓越不是單一的舉動,而是習慣

本書將習慣定義為,“知識”、“技巧”與“意愿”相互交織的結果。知識是理論范疇,指點我們做什么及為何做;技巧告訴我們如何做;意愿促使我們想要做。要養成一種習慣,我們必須具備這三點。

通過在知識、技巧與意愿三方面的努力,我們可以突破多年思維定式的偽保護,使個人和人際關系效能都更上一層樓。本書中的七個習慣并非零散的心理法則,它符合成長規律,讓我們依次經歷“成熟模式”。

“成熟模式圖”即人類成長的三個階段,分別為依賴期、獨立期、互賴期。各個時期表現形式如下:

依賴:圍繞著這個觀點——有錯誤,我怪你。

獨立:著眼于這個觀念——我可以獨立,我可以自己負責,我可以自由選擇。

互賴:從我們這個觀念出發——我們可以自主、合作、集思廣益,共同開創未來。

因此,本書先講述七個習慣中的前3個,著重在如何自我約束,由依賴進步到獨立,這些習慣屬于“個人領域的成功”范疇,是培養品德的基礎;而后才是“公眾領域的成功”,即習慣4、5、6所講授的團結、合作與溝通;第7個習慣則涵蓋了其他6個習慣,談的是自我更新。

第一部分 個人的成功:從依賴到獨立

習慣一:積極主動-個人愿景的原則

人性的本質是主動而非被動的,人類不僅能針對特定環境選擇回應方式,更能主動創造有利的環境。

采取主動不等于膽大妄為,惹事生非或滋事挑釁,而是讓他們充分認識到自己有責任創造條件。

時下盛行的社會觀點認為,環境與條件對我們起著決定性的作用。我們不否認條件作用的影響巨大,但并不等于承認它凌駕于一切之上,甚至可以決定我們的命運。

在外界的刺激與最后的回應之間,人擁有選擇的自由,這也是人與動物之間最大的不同。

從上圖可以看出,在刺激和回應之間的距離,就是我們選擇的自由,當我們能夠合理地利用這段距離時,我們往往可以收獲幸福和成功。就如面對困境時,我們可以自由地選擇應對方式,而不是逆來順受又或是條件反射。

積極主動的人改變習慣、手段和看法來解決三類問題:可直接解決的、可間接解決的、無法解決的問題,對力不能及之事處之泰然,對能掌握的事全力以赴。

對于錯誤的回應會影響到下一刻發生的事情,積極主動者承認錯誤并改正吸取教訓。

史蒂芬?柯維指出,看一個人的時間和精力集中于哪些事物,就可以大致判斷出他是否積極主動。作者將我們關注的問題分成兩類:關注圈和影響圈

關注圈,是指我們關注的問題,包括健康、子女、世界局勢等。

影響圈,則是指我們能夠影響或者改變的事情,比如學習、工作。而有些事情是我們關注,但無法影響的,比如石油危機、戰爭、飛機失事等,這些事情就屬于關注圈而不屬于影響圈。兩者的關系如下圖所示:

而積極主動和消極被動人的區別就在于,積極主動的人專注于“影響圈”,做自己力所能及的事,他們能使影響圈不斷擴大。

**消極被動的人則全神貫注于“關注圈”,**緊盯他人弱點以及超出個人能力范圍的事情不放,結果就越來越怨天尤人,從而造成影響圈日益縮小。

如何養成積極主動的習慣?

史蒂芬?柯維指出,日常生活中的種種瑣事就可以訓練我們養成積極主動的習慣。比如,我們如何面對交通堵塞、如何應對他人無理的要求、如何看待自己的問題,以及使用什么樣的語言。

實際上,從一個人的言談上,就多半可以看出他是積極主動還是消極被動的。如下表所示:

可以看出,**消極被動的語句多半帶有假設性質,而積極主動的語言則是“由內而外”改變,**即先改變自己的行為,然后再去施加影響,改變環境。

習慣二:以終為始-自我領導的原則

太多人成功之后,反而感到空虛;得到名利之后,卻發現犧牲了更可貴的事物。

因此,我們務必掌握真正重要的愿景,然后勇往直前堅持到底,使生活充滿意義。

“以終為始”,意思是說做事之前,認清方向。特別是人生目標,別被名利所蒙蔽。蓋棺定論時,你希望獲得的評價,才是你心中的真正渴望的目標。

1、“以終為始”的兩個原則基礎:

①任何事物都是兩次創造而成

第一次創造——心智,我們做任何事都是先在頭腦中構思。

第二次創造——體力,付諸實踐。

高效能人士,在行動前就能清晰地看到自己在人生各個方面所期望的結果。

②自我領導

很多人連自己的價值觀都沒有搞清楚,就忙于提高效率,制定目標或完成任務,這就是個人生活中領導意識匱乏的表現。以終為始就意味著,我們要帶著清晰的方向和價值觀來扮演自己的角色,要為自己人生的第一次創造負責。從而使決定行為和態度的思維定式真正符合自己的價值觀和正確原則。

2、以終為始最有效的方法

撰寫一份個人使命宣言,即人生哲學或基本信念。范例如下圖:

對于個人來說,基于正確原則的個人使命宣言是評價一切的標準,它將成為個人的憲法,成為我們以不變應萬變的力量源泉。它既是做出任何關鍵抉擇的基礎,也是在千變萬化的環境和情緒下做出日常決策的基礎。

確立人生使命,須從影響圈的核心開始。核心是一切思想觀念(安全感、人生方向、智慧和力量)的根本。

安全感代表價值觀、認同、自尊自重與歸屬感;

人生方向是生命的追求方向以及決斷所依據的準則;

智慧是對事物的認知、理解和判斷能力;

力量則指采取行動、達成目標的能耐。

這四者相輔相成,安全感與明確的方向可以帶來智慧,智慧則能激發行動。若四者十分健全且均衡發展,便能產生高尚的人格、平和的個性與完美正直的個體。

3、樹立正確的生活中心

無論你是否意識到,人人都有生活中心,有人以家庭為生活中心、有人以工作為中心、有人以名利為中心、有人以自我為中心等等。

它們對生活各方面的強烈影響毋庸置疑。但上述幾種生活中心都是多變的,作者提議我們要以原則為生活中心,因為原則是恒久不變、歷久彌新的。

以永恒不變的原則為生活中心,就能建立高效能的思維定式,也就能正確審視所有其他的生活重心。(見下圖)

以原則為生活中心的人總是見解不凡,思想行為也自成一格。由于擁有堅實的內在為基礎,所獲得的高度安全感、人生方向、智慧與力量,使其能享有操之在我且充實的一生。

習慣三:要事第一-自我管理的原則

有效管理是掌握重點式的管理,它把最重要的事放在第一位。由領導決定什么是重點后,再靠自制力來掌握重點,時刻把它們放在第一位,以免被感覺、情緒或沖動所左右。

習慣三落實了前兩個習慣,它通過獨立意志的發揮,建立以原則為中心的處事態度,進而達到有效的自我管理。自我管理就是指要事第一,先做最重要的事情。

所謂重要的事情是指,你個人覺得有價值及對你的使命、價值觀、對優先目標具有貢獻的活動,會使你的生命更豐富、更有意義的事,但是這些事情多數是不急迫的。因此,我們需要學習運用第四代時間管理矩陣

第四代時間管理矩陣與以往時間管理方法截然不同之處,它根本否定“時間管理”這個名詞,主張關鍵不在于時間管理,而在于個人管理。與其著重于時間與事務的安排,不如把重心放在維持產出與產能的平衡上。根據個人管理理論,將耗費時間的事務依據緊迫性與重要性分為四類。(見下圖)

對這四類事務的偏重,將導致截然不同的結果:

①偏重第一類事務

這類事務通常被稱為“危機”,如果你過分注重第一類事務,那么它們的范圍就會變得越來越大,最終占據你全部的時間和精力。結果:壓力大、精疲力盡、被危機牽著鼻子走、忙于收拾殘局。

②偏重第三類事務

有人將大部分時間花在第三類事務上,卻自以為在致力于第一類事務。他們整天忙于應付一些自認為十分重要的緊急事件,殊不知緊迫之事往往只是別人的優先,對別人很重要,對自己就不一定了。結果:急功近利、被危機牽著鼻子走、被視為巧言令色、輕視目標和計劃、人際關系膚淺。

③偏重第三、四類事務

有些人幾乎將所有的時間都用在第三和四類事務上,可以說他們過的是一種不負責任的生活。結果:完全不負責任、被炒魷魚、基本生活都需要依賴他人。

④偏重第二類事務

高效能人士總是能避免陷入第三和第四類事務,他們還會花費更多時間在第二類事務上,減少第一類事務的數量。結果:愿景、遠見、平衡、自律、自制、很少發生危機。

總的來說,普通人的時間安排與高效能人士的時間安排對比如下:

若想做到把時間和精力集中到第二象限的活動上,需要以下四項關鍵步驟:

①確認角色

作為一個個體你有屬于自己的各種角色,先寫出你自己的關鍵角色,再列舉自己想要持續投入時間和精力去做的事情,只要考慮下一周的角色和任務

②選擇目標

就是思考下一個周計劃中每一任務欄下你最想做的一兩件要事,作為你選定的目標。

③安排進度

為每一項目標安排具體的實施時間。

④每日調整

根據突發事件、人際關系的意外發展及嶄新機會對每天的要務安排進行適當調整。

如果能夠建立以第二類事務為中心的思維定式,就能提高安排生活的能力,能夠真正做到要事為先,言出必行。從此,就可以有效管理自己的生活,實現個人的獨立,不必再求助于他人。

第二部分 公眾領域的成功:從獨立到互賴

習慣四:雙贏思維-人際領導的原則

雙贏者把生活看作一個合作的舞臺,而不是一個角斗場。一般人看事情多用二分法:非強即弱,非勝即敗。其實世界之大,人人都有足夠的立足空間,他人之得不必就視為自己之失。

雙贏思維是一種基于互敬、尋求互惠的思考框架與心境,目的是爭取更豐盛的機會、財富與資源,而不是你死我活的敵對競爭。

雙贏不是什么技巧,而是人際交往的哲學,是六個交往模式之一,這六個模式分別是:

①利人利己(雙贏):為自己謀利也不忘他人

②損人利己(贏/輸):攀比、競爭、追求地位、權力欲

③損己利人(輸/贏):委曲求全、討好他人

④兩敗俱傷(輸/輸):總是嫉妒或批判他人

⑤獨善其身(贏):一心求勝,不顧他人,自我為中心

⑥好聚好散(無交易):買賣不成仁義在

以上6種交往模式,哪一種最好?

最好的選擇是視情況而定,如果贏要以過多的時間和精力為代價,以至于得不償失,那么還是“退一步海闊天空”的好;如果你十分珍惜某一人際關系,而牽涉的問題又無足輕重,那么偶爾以輸/贏模式來肯定對方也無妨。

但實際上,大多數情況都只是相互依賴的大環境的一部分,于是只有雙贏模式才是唯一可行的

雙贏的原則是所有人際交往的基礎,包括5個獨立的方面。(見下圖)

“雙贏品德”是基礎,接著建立起“雙贏關系”,由此衍生出“雙贏協議”,需要“雙贏體系”作為培育環境,通過雙贏的“雙贏過程”來完成。這也是雙贏思維的5個要領。

對于我們個人來說,形成雙贏思維的一個重要方式便是,培養雙贏品德。雙贏品德有以下3個基本特征:

①誠信

即自己的價值觀。如果我們不了解“贏”的真正含義及其與我們內心價值觀的一致性,那么就不可能做到“贏”。沒有了誠信的基礎,雙贏不過是一種無效的表面功夫。

②成熟

這是敢作敢為和善解人意之間的一種平衡狀態。成熟就是在表達自己的情感和信念的同時,又能體諒他人的想法和感受的能力。下圖為不同人際觀的成熟度:

在敢作敢為和善解人意之間找到平衡點,才是真正的成熟,這是雙贏的基礎

③知足

即相信資源充足,人人有份。

牢記一點:當你超越環境、態度和行為,將觸角探到自己的內心,會發現雙贏和所有其他正確原則一樣,本就深植在我們的生活中

雙贏并非性格魅力的技巧,而是人類交往的一種模式。雙贏來自誠信、成熟和知足的人格,是高度互信的結果;它體現在能有效闡明并管理人們的期望和成就的協議中;在起支持作用的雙贏體系里蓬勃生長;經由必要的雙贏過程來實現。

習慣五:知彼解己-移情溝通的原則

若要用一句話歸納我在人際關系方面學到的一個最重要的原則,那就是:知彼解己。

首先尋求去了解對方,然后再爭取讓對方了解自己。這一原則是進行有效人際交流的關鍵。

如果你想養成真正有效的人際溝通習慣,就不能單靠技巧,首先你要“知彼”。這一點是交往模式的一大轉變,因為我們通常把讓別人理解自己放在首位,大部分人在聆聽時并不是想理解對方,而是為了做出回應。

因此,“知彼”的關鍵在于移情聆聽,這至少包括以下4個階段:

第一階段是復述語句,這至少能使人專心聆聽

案例:

子:“上學真是無聊透了!”

父:“你已經受不了了,覺得上學太無聊。”

第二階段加入解釋,純用自己的語句表達

父:“你不想上學了。”

第三階段滲入個人的感覺,此時聽者所注意的已不止于言語,也開始體會對方的心情

父:“你覺得很有挫折感。”

第四階段是既加以解釋,又帶有感情

父:“你對上學有很深的挫折感。”

此外,表達自己也是謀求雙贏之道所不可缺少的,了解別人固然重要,但我們也有義務讓自己被人了解。

古希臘人有一種很經典的哲學觀點,即品德第一,感情第二,理性第三。請注意這個順序,首先是你本身的品德,然后是你同他人關系,最后是你表達自己的能力,這是另外一種重要的模式轉換。

習慣六:統合綜效-創造性合作的原則

統合綜效的基本心態是:如果一位具有相當聰明才智的人跟我意見不同,那么對方的主張必定有我尚未體會的奧妙,值得加以了解。

與人合作最重要的是,重視不同個體的不同心理、情緒與智能,以及個人眼中所見到的不同世界。假如兩人意見相同,其中一人必屬多余。與所見略同的人溝通,毫無益處,要有分歧才有收獲。

通常來說,溝通可以簡單地分為以下三層次:

①低層次的溝通

此層次源自低度信任,其特點是人與人之間互相提防,步步為營,經常借助法律說話,為情況惡化作打算,其結果只能是贏/輸或者輸/贏。

②中間層次的溝通

此層次是互相尊重式的,他們可以理性地理解別人,卻無法站在對方的立場上真正理解他們的模式和設想。這種溝通層次在獨立的,甚至在相互依賴的環境中尚有立足之地,但并不具備創造性。

③統合綜效

這意味著1+1等于8或16,甚至1600。源自高度信任的統合綜效能帶來比原來更好的解決方案,每一個參與者都能認識到這一點,并全心享受這種創造性的事業。

簡單地說,統合綜效就是整體大于部門之和。它的基本心態是,如果一位具有相當聰明才智的人跟我意見不同,那么對方的主張必定有我尚未體會的奧妙,值得加以了解。精髓是判斷和尊重差異,取長補短

尊重人與人之間的差異,當有人不同意你的觀點的時候,你應該試著尋找統合綜效的的第三條道路,一般條件下它總是存在的。如果你堅持雙贏模式,確實愿意努力理解對方,你就能找到一種能讓每一個人都受益更多的解決方案。

第三部分自我提升和完善

習慣七:不斷更新

人生最值得的投資就是磨練自己,因為生活與服務人群都得靠自己,這是最珍貴的工具。

工作本身并不能帶來經濟上的安全感,具備良好的思考、學習、創造與適應能力,才能立于不敗之地。擁有財富,并不代表經濟獨立,擁有創造財富的能力才真正可靠。

如果你在森林中看到一名伐木工人,為了砍一棵樹已辛苦工作了5個小時,精疲力竭卻進展有限,你想必會建議他:“為什么不暫停幾分鐘,把鋸子磨得更鋒利?”

然而對方卻回答:“我沒空,鋸樹都來不及,哪有時間磨鋸子?”

看到這個答案,大部分人都會瞠目結舌。但事實上,很多人在人生路上就如同這位鋸樹的人,只顧著一味往前趕路,卻忘了“更新自己”。我們要明白,人生最值得的投資就是磨煉自己,因為生活與服務人群都得靠自己,這是最珍貴的工具

自我更新有以下4個層面:

①身體層面

通過正常適量的營養、運動、休息及壓力管理來維持生理健康。

②心智層面

通過閱讀、寫作,思考完成心智更新。

③精神層面

通過閱讀啟發性書籍、接觸大自然。

④社會情感層面

通過持續增加情感投資來更新。

以上四個層面的更新都很重要,因此只有平衡好四個層面的更新進度,才能取得最理想的效果

“每天的個人領域的成功”(每天至少用一個小時實現身體、精神和智力層面的更新)是培養七個習慣的關鍵。

歌德( Goethe)說:“以一個人的現有表現期許之,他不會有所長進。以他的潛能和應有成就期許之,他定能不負所望。”

總結回顧

本書共闡述了高效能人士的七個習慣,這七個習慣符合成長規律,共分為三個階段。(見下圖)

第一部分,由依賴進步到獨立,屬于“個人領域的成功”范疇。在這一過程中,我們需要培養的是積極主動、以終為始、要事第一這3個習慣。

第二部分由獨立到互賴,屬于“公眾領域的成功”范疇。在這一過程中,我們需要培養的是雙贏思維、知彼解己、統合綜效這3個習慣。

第三部分,自我提升和完善,則涵蓋了其他6個習慣,談的是第7個習慣自我更新。通過這一習慣來統合前6個習慣,實現7個習慣的良性循環。

作者:ThinkWon 發表于 2020/10/06 17:09:03 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/108941111
閱讀:5205 評論:4 查看評論
]]>
<![CDATA[[原]Java是編譯型還是解釋型語言]]> http://www.gifted-edu.com/ThinkWon/article/details/108678327 http://www.gifted-edu.com/ThinkWon/article/details/108678327 ThinkWon 2020/09/19 10:53:20

1.編譯型語言和解釋型語言

編譯型語言

定義:在程序運行之前,通過編譯器將源程序編譯成機器碼(可運行的二進制代碼),以后執行這個程序時,就不用再進行編譯了。

優點:編譯器一般會有預編譯的過程對代碼進行優化。因為編譯只做一次,運行時不需要編譯,所以編譯型語言的程序執行效率高,可以脫離語言環境獨立運行。

缺點:編譯之后如果需要修改就需要整個模塊重新編譯。編譯的時候根據對應的運行環境生成機器碼,不同的操作系統之間移植就會有問題,需要根據運行的操作系統環境編譯不同的可執行文件。

總結:執行速度快、效率高;依靠編譯器、跨平臺性差些。

代表語言:C、C++、Pascal、Object-C以及Swift。

解釋型語言

定義:解釋型語言的源代碼不是直接翻譯成機器碼,而是先翻譯成中間代碼,再由解釋器對中間代碼進行解釋運行。在運行的時候才將源程序翻譯成機器碼,翻譯一句,然后執行一句,直至結束。

優點:有良好的平臺兼容性,在任何環境中都可以運行,前提是安裝了解釋器(虛擬機)。靈活,修改代碼的時候直接修改就可以,可以快速部署,不用停機維護。

缺點:每次運行的時候都要解釋一遍,性能上不如編譯型語言。

總結:執行速度慢、效率低;依靠解釋器、跨平臺性好。

代表語言:JavaScript、Python、Erlang、PHP、Perl、Ruby。

混合型語言

定義:既然編譯型和解釋型各有缺點就會有人想到把兩種類型整合起來,取其精華去其糟粕,就出現了半編譯,半解釋型語言。

比如C#,C#在編譯的時候不是直接編譯成機器碼而是中間碼,.NET平臺提供了中間語言運行庫運行中間碼,中間語言運行庫類似于Java虛擬機。.NET在編譯成IL代碼后,保存在dll中,首次運行時由JIT在編譯成機器碼緩存在內存中,下次直接執行。嚴格來說混合型語言屬于解釋型語言,C#更接近編譯型語言。

Java即是編譯型的,也是解釋型語言,總的來說Java更接近解釋型語言

  • 可以說它是編譯型的。因為所有的Java代碼都是要編譯的,.java不經過編譯就什么用都沒有。同時圍繞JVM的效率問題,會涉及一些如JIT、AOT等優化技術,例如JIT技術,會將熱點代碼編譯成機器碼。而AOT技術,是在運行前,通過工具直接將字節碼轉換為機器碼。

  • 可以說它是解釋型的。因為Java代碼編譯后不能直接運行,它是解釋運行在JVM上的,所以它是解釋運行的。

2.動態類型語言和靜態類型語言

動態類型語言

動態類型語言:在運行期間才去做數據類型檢查的語言,說的是數據類型。動態類型語言的數據類型不是在編譯階段決定的,而是把類型綁定延后到了運行階段。

代表語言:Python、Ruby、Erlang、JavaScript、Swift、PHP、Perl。

靜態類型語言

靜態類型語言的數據類型是在編譯期間(或運行之前)確定的,編寫代碼的時候要明確確定變量的數據類型。

代表語言:C、C++、C#、Java、Object-C。

3.動態語言和靜態語言

動態語言

動態類型語言和動態語言是完全不同的兩個概念。

動態語言:說的是運行時改變結構,說的是代碼結構。在運行時可以改變其結構的語言:例如新的函數、對象、甚至代碼可以被引進,已有的函數可以被刪除或是其他結構上的變化。通俗點說就是在運行時代碼可以根據某些條件改變自身結構。

代表語言:Object-C、C#、JavaScript、PHP、Python、Erlang。

靜態語言

與動態語言相對應的,運行時結構不可變的語言就是靜態語言。如Java、C、C++。

作者:ThinkWon 發表于 2020/09/19 10:53:20 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/108678327
閱讀:3904 評論:2 查看評論
]]>
<![CDATA[[原]斯坦福高效睡眠法-讀書筆記]]> http://www.gifted-edu.com/ThinkWon/article/details/108349844 http://www.gifted-edu.com/ThinkWon/article/details/108349844 ThinkWon 2020/09/01 20:15:10

文章目錄


在這里插入圖片描述

序言 斯坦福的完美睡眠法

作者

西野精治,斯坦福大學睡眠研究所所長

斯坦福大學睡眠研究所

斯坦福大學睡眠研究所號稱“世界第一睡眠研究所”,從事睡眠研究超過40年,有大量成果發表在Nature、Science等頂級學術期刊上。據說,全美國現在睡眠診所數量已經有2000~3000家。這表明人們對于睡眠的關注度很高,并且很多人都有睡眠方面的困擾

最佳睡眠

睡眠期間,保持大腦和身體都處于最佳狀態,才能真正實現高質量睡眠。確保最佳的睡眠,能使白天的效率達到最大化

睡眠的重要性

在1天的24個小時中,睡眠占據了大部分的時間,睡眠質量的好壞,直接影響著我們的工作學習和生活。

不過,大部分人還是低估了睡眠的重要性。除了對工作有重要影響,睡眠不好還會引起肥胖、糖尿病、老年癡呆等病癥,甚至導致驟死。所以保證睡眠質量是造就完美人生的基礎

第一二章 睡眠基礎認知

第一章 睡得多不等于睡得好
第二章 為什么人生1/3的時間都在睡覺

睡眠負債

  • “睡眠負債”,是指睡眠不足一旦堆積,就像欠債一樣,人們會無力償還,債臺高筑,最終大腦和身體都會不受控制,導致睡眠的自行“破產”。
  • 睡眠負債會給大腦和身體帶來損害,從而縮短壽命。睡眠負債也會造成肥胖(所以想減肥的小伙伴們一定要保證睡眠的質量)。另外,“睡過頭”也不是件好事。研究表明每天午休超過1個小時,會加大患癡呆癥和糖尿病的風險。
  • 當我們償還清睡眠負債,保證良好的睡眠質量,消除對睡眠的不滿足感,大腦和身體的狀態就會提高,注意力渙散,身體狀態不佳等消極問題也會隨之消失。

遺傳基因決定理想的睡眠時間

  • 有些動物能在一定的時間段里不睡覺。例如,帝企鵝在孵小企鵝的1~2個月時間里,基本不睡覺。
  • 美國高中生挑戰吉尼斯不眠記錄,實現連續11天不睡覺。畢竟攜帶短時睡眠基因的人很少,對于絕大部分人來說,我們不同于帝企鵝等動物,遺傳基因決定了我們一天需要大部分的睡眠時間

睡眠不足的危害

  • 極易出現瞬時睡眠
  • 睡眠負債會縮短壽命
  • 不睡覺的人患各種疾病的概率大大提高

睡眠的使命

  • 讓大腦和身體得到休息
  • 整理記憶,并讓其扎根于腦中
  • 調節激素的平衡
  • 提高免疫力,遠離疾病
  • 排除大腦中的廢棄物

多做夢比較好

  • REM的夢多是故事性的
  • 非REM的夢多是抽象的

不可忽視的睡眠共性

運動員的睡眠方式

  • 除了運動員以外的普通人也一樣,越是體重偏重、身材健壯的人越會選擇較硬的床墊
  • 正式選手更講究睡覺

精英人士都會有意識地逃離垃圾睡眠

促進睡眠的認知行為療法

  • 睡眠與大腦有很深的關聯。不借助藥物治療失眠癥的方法,稱為認知行為療法
  • 不依賴藥物和酒精,尊重身體情況

睡眠質量決定清醒的程度

睡眠的認識誤區

  • 決定睡眠的不是“量”,而是“質”
  • 利用周末補覺,其實效果并不佳
  • 并不是每個人每天都需要7個小時的睡眠時間
  • 在睡覺前會攝入大量的酒精助眠是錯誤的

如何了解睡眠的質量

  • 可以使用多導睡眠監測儀進行監測,但是檢測難度很大
  • 對于普通人來說,如果第二天狀態良好,那就說明睡眠質量好

死亡率高達40%的睡眠障礙

  • 睡眠呼吸暫停綜合征

  • 經常打呼嚕就是表征之一

    • 造成各種困擾,影響身體健康
    • 可以通過CPAP(持續正壓通氣)呼吸機很簡單的改善
  • 打呼嚕容易導致牙齒變形

睡眠革命

  • 重視睡眠,提高睡眠質量,才能擁有更好的生活

第三章 黃金90分鐘睡眠法則

黃金90分鐘:培養最強大腦和體魄

判斷睡眠質量好壞的關鍵

  • “白天是否容易犯困”,“頭腦是否清醒”,“工作中是否出現很多失誤”等白天的清醒程度,才是判斷睡眠質量好壞的關鍵。

最初的90分鐘

  • 非REM睡眠:屬于深度睡眠,臨近黎明時會變淺,時間會變短
    REM睡眠:屬于淺度睡眠,臨近黎明時,時間會變長
  • 決定睡眠質量的關鍵在于入睡后最開始的90分鐘。如果在最初的90分鐘就進入深度睡眠,就能夠實現最佳睡眠。
  • 堅持每天同一時間睡覺、同一時間起床是最簡單的獲得黃金90分鐘睡眠的方法。
  • 從入睡到醒來,人并非一直保持同一狀態。睡眠的類型,包括REM睡眠(大腦已經清醒,但身體還處于熟睡的一種狀態)和非REM睡眠(大腦和身體都處于沉睡中的一種狀態)兩種。在睡覺的過程中,這兩種睡眠狀態會交替反復出現。

不得不加班的夜晚怎么度過

  • 如果加班,先睡90-120分鐘,等黃金90分鐘和第一次深度睡眠周期結束后,再繼續工作。
  • 熬夜到黎明睡覺,對身體傷害很大,而且工作狀態很糟糕

黃金90分鐘:決定睡眠質量

喝酒不會提高睡眠質量

  • 一定不要忽視最初的困意,明明犯困卻堅持不睡,之后就很難進入到深度睡眠狀態,而且無論睡多久都不會擁有好的睡眠

健康人閉上眼10分鐘就能睡著

  • 無論睡多久,如果一開始90分鐘睡眠質量不好,整個睡眠都不行
  • 如果一開始90分鐘睡得好,即使總時間短,白天也會有精神

睡眠周期一般是90分鐘

  • 因人而異,90-120分鐘之間
  • 如果先休息再工作的話,盡量保持先睡90分鐘

黃金90分鐘的三大優點

  • 調節自律神經
  • 促進生長激素分泌
  • 讓大腦狀態趨于良好

第四章 斯坦福高效睡眠法

用體溫和大腦,打造最佳睡眠

入睡潛伏期

  • 進入睡眠狀態所需的時間稱為入睡潛伏期,容易入睡和難以入睡的人之間,差值僅僅為2分鐘
  • 要想排除干擾自己入睡的因素,必須要操控好體溫和大腦這兩個重要的睡眠開關

體溫和大腦,睡眠的兩大開關

  • 立刻酣睡的方法

    • 固定上床時間
    • 調節體溫和大腦,快速入睡
  • 體溫開關

    • 縮小體內溫度和體表溫度差值
  • 腦部開關

    • 寧靜幽暗的環境

提升睡眠質量的三大體溫開關

調節體溫的關鍵

  • 體表溫度上升,熱量散發導致體內溫度下降,讓人快速入睡
  • 黃金90分鐘內降低體內溫度

入睡前90分鐘沐浴

  • 先提升溫度,然后就會快速下降
  • 事例:如果在0點睡覺,流程應該這樣,22點,澡盆泡上15分鐘;22點半,沐浴完畢;0點上床;0點10分即可睡著
  • 淋浴也可以,不會讓體內溫度過高的溫水浴,但沐浴后盡量不要穿不能排汗的長袍

足浴具有驚人的散熱能力

  • 改善腳部的血液循環
  • 散熱效果好,花費時間短
  • 比較好操作,最適合繁忙的商務人士,也適合較懶的普通人

穿襪子睡覺對睡眠無益

室溫調節

  • 合適的室溫,溫度過高不利于排汗,溫度稍低容易入睡,但是溫度過低容易感冒

利用腦部開關將睡眠模式化

將大腦放空,什么都不去思考

單調法則

  • 什么都別想,看無聊的東西

  • 突破大腦的關口

    • 熟悉的環境、衣服
    • 養成的習慣就不要改了:看電視劇、看書等,但要選擇刺激性小的讀物

數羊

  • 可能會有用,主要是單調
  • 外國人數羊,中國人數水餃

抖腿不利于入睡

大腦不想睡覺的時候

人為何犯困

  • 苯基二氫喹唑啉,具有強效喚醒作用的神經傳導物質

臨睡前卻不想睡

  • 臨睡前兩個小時,避免進入睡眠禁區

明天必須早起怎么辦

  • 不要勉強自己,仍然按平常的時間入睡

嚴格遵守固定的睡眠作息

  • 防止進入睡眠禁區
  • 形成模式化的睡眠

即有害又有益的光

  • 光線影響褪黑素的分泌,褪黑素是一種促進睡眠的激素
  • 藍光讓身體清醒
  • 避免在漆黑的夜晚長時間玩手機

第五章 斯坦福終極清醒戰略

清醒時的狀態,也決定了能否睡得香

  • 清醒時的狀態,也決定了能否睡得香,“睡眠”與“清醒”互為一體。
  • 保持清醒有兩個關鍵,光和體溫,它們共同造就了良好的清醒狀態。

斯坦福清醒戰略

清醒戰略1設定兩個鬧鐘

  • 預留起床空窗期:假設早上7點必須起床,可以將鬧鐘時間分別設定為6點40和7點,6點40分到7點之間的20分鐘,就是所謂的起床空窗期
  • 第一次的鬧鐘,要選擇音量小且時間短的鈴聲。
  • 不要因為今天沒什么事就懶床
  • “早晨醒得早,但就是不想離開被窩”這也是抑郁癥的一種前兆。

清醒戰略2遠離誘惑睡眠的物質

  • 光線可以調節人的晝夜節律,起床后無論什么天氣,沐浴一下清晨的日光是極其簡單有效的清醒方式,曬太陽同時可以抑制褪黑素分泌,更為清醒

清醒戰略3光腳有助于保持清醒

  • 接觸地板有助于刺激大腦上行性網狀結構,有助于清醒
  • 光腳導致體表溫度降低,拉大表內溫度差異,避免犯困

清醒戰略4洗手

  • 用冷水洗手

清醒戰略5咀嚼有助于強化睡眠和記憶

  • 咀嚼可以刺激三叉神經
  • 細嚼慢咽,防止肥胖

清醒戰略6盡量避免汗流浹背

  • 早晨運動過多會疲憊,體溫過高會發困,建議快步走

清醒戰略7咖啡

  • 咖啡因能幫助我們驅散睡意和疲憊,同時也能與長時間清醒積累的睡眠壓力相抗衡

清醒戰略8改變做重要工作的時間

  • 將重要工作、用腦工作盡量安排到上午完成
  • 會議、查找文獻、不需要過多思考的工作在午餐后

清醒戰略9不吃晚飯也會影響睡眠質量

  • 不吃晚飯的話,不僅會導致苯基二氫喹唑林增加、食欲旺盛、睡不著覺等問題,還會使自律神經紊亂

清醒戰略10冰鎮西紅柿有助于促進睡眠

  • 為了夜晚睡得舒服,晚飯時使用能降低體內溫度的食物也是一種方法

清醒戰略11飲酒助于黃金睡眠

  • 飲酒量一定要少,少于100毫升

特別篇:消滅時差影響的斯坦福出差策略

  • 在出發之前就按目的地節律生活
  • 不建議吃航空餐

第六章 能控制睡意的人,也能掌控自己的人生

睡意是好還是壞

為何我們會犯困

  • 睡眠負債
  • 晝夜節律或90-120分鐘的亞晝夜節律等體內生物鐘方面出現問題

早晨起床不清醒

  • 睡眠負債,睡得不足
  • 可能是睡眠呼吸綜合征:打呼嚕
  • 飲酒、生活節奏被打亂

吃不吃午飯都犯困

  • 午飯并非主要原因,主要是睡眠負債
  • 午飯少吃點,少攝入淀粉
  • 吃飯應該細嚼慢咽

無聊會議中的困意

抗瞌睡法

會議中積極提問

  • 會議短,參加人精干,討論熱烈

控制清醒的神經細胞

  • 細嚼慢咽,吃口香糖
  • 喝咖啡,或有咖啡因的食物,綠茶紅茶也含有咖啡因
  • 促進手部血管擴張

快速恢復能量的小睡方法

小睡能讓大腦迅速恢復

  • 小睡前5分鐘,手里拿溫熱的東西,可以順利入睡

超一流的能量午睡方法

  • 小睡20分鐘
  • 短時間的睡覺對大腦有利,但超過1小時容易讓人癡呆
  • 碎片化的睡眠不好,不能過于依賴

高質量的周末睡眠

  • 哪怕早晨多睡,上床時間也要一致
  • 周一早上召開例會
  • 周一安排重要任務

改變人生的1/3,也會影響剩下的2/3

許多事情只有睡眠能做到

  • 預防疾病
  • 預防受傷和生產事故的發生
  • 心理輔導,傷病治療
  • 提升工作表現

最好的禮物

  • 對除睡覺以外的人生來說,睡眠也是一件很棒的禮物
作者:ThinkWon 發表于 2020/09/01 20:15:10 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/108349844
閱讀:6630 評論:2 查看評論
]]>
<![CDATA[[原]高效休息法-讀書筆記]]> http://www.gifted-edu.com/ThinkWon/article/details/108349809 http://www.gifted-edu.com/ThinkWon/article/details/108349809 ThinkWon 2020/09/01 20:13:02

文章目錄


在這里插入圖片描述

1.科學正確的“大腦休息法”

正念(Mindfulness)

定義

不做任何評價和判斷,主動將注意力集中在當下的經驗上。它不僅可以改變大腦的“運作狀況”,還能夠進一步預防疲勞。在某項研究中,甚至發現它能夠抑制壓力激素——皮質醇的生成。我們很有可能借助正念,創造出一個具有高度抗壓性的大腦

基本原理

掌握正念冥想,就能夠抑制DMN的關鍵部位,避免雜念對大腦能量的消耗

預設模式網絡(DefaultMode-Network,簡稱DMN)

定義

所謂DMN (Default Mode-Network,預設模式網絡),即由大腦的內側前額葉皮質、后扣帶皮層、楔前葉、頂葉頂下葉等構成的大腦網絡。它會在大腦未執行有意識活動時,自動進行基本操作。換言之,就是大腦的“低速空轉”狀態,讓大腦成為一種總是動個不停的器官。

特征

  • 大腦能量吞噬者,消耗大腦60%~80%能量
  • 無所事事發呆時DMN仍在工作

DMN過度

反芻思考

患有抑郁癥的人經常會反復出現“當時要是這么做就好了”的消極情緒,這就是所謂的反芻思考。這種思考和大腦疲勞直接相關,同時被指出也和DMN的過渡使用有關

高效休息法的目的

大腦具有可塑性,堅持實踐正念的話,你將會擁有一個不易疲勞的大腦。希望大家能通過本書來改變你的大腦,掌握高度集中注意力的方法,畢竟這才是“高效
休息法”的最終目的。

2.消除大腦疲勞的七個休息法

1.感覺腦袋昏昏沉沉時——正念呼吸法

目標與原因分析

  • 容易疲憊的大腦,無法關注“當下”
  • 注意力渙散、無精打采、焦躁不安等都是大腦疲勞的征兆。其根本原因就在于,意識始終關注著過去和未來,就是不關注“現在”。當這種情況成為習慣時,便很容易造成大腦疲勞。

改善

  • 減輕壓力,抑制雜念
  • 提高注意力和記憶力
  • 控制情緒
  • 改善免疫力

步驟

  • ①采取基本姿勢

    • 坐在椅子上,稍微挺直背部,離開椅背。
    • 腹部放松,手放在大腿上,雙腿不交叉。
    • 閉上眼睛。如果采用睜著眼睛的方式,則雙眼望向前方2米左右的位置。
  • ②用意識關注身體的感覺

    • 感受與周圍環境的接觸(腳底與地板、屁股和椅子、手和大腿等)。
    • 感受身體被地球重力吸引。
  • ③注意呼吸

    • 注意與呼吸有關的感覺(通過鼻孔的空氣/因空氣出入而導致胸部與腹部的起伏/呼吸與呼吸之間的停頓/每一次呼吸的深度/吸氣與呼氣的空氣溫度差異等)。
    • 不必深呼吸也不用控制呼吸,感覺就像是“等著”呼吸自然到來。
    • 為呼吸貼上“1”“2”……“10”的標簽也很有效果。
  • ④如果浮現雜念……

    • 一旦發現自己浮現雜念,就將注意力重新放到呼吸上(呼吸是“意識的錨”)。
    • 產生雜念是很正常的,不必苛責自己。

關鍵點

  • 5分鐘也好,10分鐘也好,重要的是每天持續實踐。
  • 要在同一時間、同一地點進行(大腦最喜歡“習慣”)。

2.心事重重時——動態冥想

目標與原因分析

  • 擺脫讓大腦疲勞的“自動駕駛狀態”
  • 當今時代,幾乎每個人都身兼數職。為了完成任務,人們往往同時要做好幾件事情。不過,在日常生活中,越是處于“自動駕駛狀態”,大腦就越容易出現雜念。這種情況一旦成為習慣,注意力和專注力就會下降。

改善

  • 改善專注力和注意力
  • 實現心流狀態(Flow State)

步驟

  • ①步行冥想

    • 步行速度任意,但建議剛開始時走慢一點。
    • 有意識地留意手腳肌肉及關節的變化、與地面接觸的感覺。
    • 給自己的動作分類,例如“左/右”“上/下”等(這樣做能夠進一步集中注意力)。
  • ②以站姿進行動態冥想

    • 站著并將雙腳打開至與肩等寬,伸出雙臂,在身體兩側緩緩抬高。
    • 將注意力集中在腕部肌肉的變化、血液下流的感覺上,還要感受重力。
    • 慢慢將手臂抬高后,再慢慢放下手臂至原位,反復重復幾次。
  • ③以坐姿進行動態冥想

    • 坐在椅子上,從后向前慢慢轉動肩膀。
    • 用心感受肌肉、關節的變化。
    • 轉動一次后,反方向再次轉動肩膀,以同樣的方式集中注意力。
  • ④其他方法

    • 有意識地關注日常生活中的動作,例如穿衣服、刷牙等。
    • 開車時可以關注屁股坐在椅子上的感覺、手握住方向盤的觸感、控制方向盤以及剎車時肌肉和關節的變化等(注意安全駕駛)。
    • 一邊做簡單的體操,一邊關注身體的變化。

關鍵點

  • 提前決定好進行動態冥想的時機有助于養成習慣。例如,“今天決定從離開家門開始動態冥想”“刷卡進地鐵站后開始動態冥想”等。
  • 吃飯時也可進行動態冥想。如關注食物的口感、食物在口腔內的觸感、唾液的變化等。

3.壓力導致身體狀態不佳時——壓力呼吸化法

目標與原因分析

  • 改善腦部結構,改變對壓力的感知方式
  • 壓力雖然是一種大腦內部現象,但是逐漸積累后會對身體造成巨大的傷害。剛開始可能只是身體疲乏或是肩酸背痛,但逐漸加重后會導致激烈的腹痛、胃腸炎等。為了防止壓力產生和惡化,可以嘗試采取從大腦(前額葉和杏仁核)開始改善的“壓力呼吸化法”

改善

  • 消除壓力
  • 消除壓力造成的緊張感(肩膀僵硬等)
  • 改善其他身體不適

步驟

  • ①注意壓力來臨時自己的變化

    • 采取正念冥想的基本姿勢。
    • 將造成壓力的原因總結成“一句話”(這樣做更易把握身體和內心的反應)。
    • 在心中默念這句話,同時感受身體和內心有何反應。
  • ②將意識集中到呼吸上

    • 給呼吸貼上“1”“2”……“10”的標簽。
    • 感受身體的緊繃慢慢舒緩、逐漸放松。
  • ③將意識擴散至全身

    • 將注意力擴散至全身(設想全身都在“呼吸”)。
    • 吸入空氣時,設想對壓力有所反應的身體部位在“吸氣”,隨著呼吸起伏,有意識地保持該部位的放松。
    • 繼續將注意力擴散至周圍的空間。

關鍵點

  • 身體疲勞的主要原因仍是大腦疲勞。
  • 將導致壓力的原因“呼吸化”后,能夠使自己的“認知扭曲”客觀化。

4.想跳脫思考怪圈時——“猴子思維”消除法

目標與原因分析

  • 讓反復在腦海中出現的“猴子思維”安靜下來
  • 本書將腦海中的過多思慮和雜念比喻成“猴子思維(monkey mind)”。思慮和雜念過多就像猴子在大腦中喧鬧一樣,會消耗大量能量,導致大腦疲勞、睡眠質量下降。這時,首先要做的就是要改變你對雜念的“認知”。只要給那些反復出現的想法“取個名字”,就能擺脫這種狀態

改善

  • 抑制某個想法的重復出現
  • 提高注意力,避免自我厭惡
  • 改善睡眠品質,容易進入深度睡眠

步驟

  • ①扔掉“胡思亂想”

    • 給想法貼上標簽,留心那些“想了很多遍”的事情。
    • 想象把那些已經“受夠了”的想法踢出大腦的感覺。
  • ②找到例外

    • 一直出現同樣的想法,是不是因為設置了同一個前提?
    • 想想一直糾結的這個想法是否有反例。
  • ③站在先賢的角度看待問題

    • 自己尊敬的人或歷史上的偉人會怎么處理呢?
    • 他們是否會將“雜念本身”和“心懷雜念的自己”等同視之呢?
  • ④不要判斷好壞

    • 你是否用了不屬于“當下”的其他標準來評判事物?
    • 要注意“不做道德評判(non-judgmental)”。
  • ⑤探索原因

    • 為什么這個想法會出現這么多次?(是因為愿望沒被實現嗎?)
    • 從自己的“深層需求(deep needs)”開始重新思考。

關鍵點

  • 要意識到“雜念=列車”而“自己=月臺”,這種認知行為療法的效果顯著。
  • 思考的重復回環會妨礙睡眠(大腦的凈化)。

5.被憤怒沖動沖昏頭腦時——RAIN法

目標與原因分析

  • 創造一個“不會被杏仁核挾持”的大腦結構
  • 大腦承受過多壓力時,控制本能和情感的杏仁核就開始失控。通常情況下,掌管理性思考功能的額葉可以抑制這種現象,只要持續冥想,你就能創造出實現兩者平衡的大腦結構。

改善

  • 平息怒氣
  • 控制欲望,抑制沖動情緒
  • 減肥
  • 戒煙

步驟

  • ①Recognize(認知)

    • 認識到內心的憤怒。
    • 不把憤怒和憤怒的自己畫上等號。
  • ②Accept(接受)

    • 接受自己憤怒的事實。
    • 對這個事實不加以價值評判,容許其存在。
  • ③Investigate(調查)

    • 觀察一下憤怒時身體有何變化?
    • 心率變化如何?
    • 身體的哪個部位感到緊繃?
  • ④Non-Identification(保持距離)

    • 不要過分糾結自己的情緒。
    • 甩掉憤怒,把憤怒設想成是他人之事。

關鍵點

  • RAIN法對于控制憤怒之外的其他沖動情緒(渴望)也很有效。
  • 目標性越強的人越不容易放松心情,更容易情緒激動。

6.看他人不順眼時——溫柔的慈悲心

目標與原因分析

  • 培養可以消除大腦疲勞的“正面情緒”
  • 每個人都有無論怎么看都不順眼的人。實際上,人的壓力大部分都來自人際關系。遇到看不順眼的人或事時,與其把精力浪費在厭惡、嫉妒、憤怒這些消極情緒上,不如花些時間多多培養“積極向上的情緒”

改善

  • 抑制對他人的負面情緒
  • 培養正面情緒

步驟

  • ①保持正念的意識狀態

    • 將平常的正念冥想持續做10分鐘。
    • 注意力從消極情緒重新集中到“當下”。
  • ②想起那個“讓你不爽”的人

    • 內心浮現那個造成你壓力的人。
    • 關注想起他(她)時的身體感覺和心情變化。
  • ③在心中對他(她)默念以下句子

    • “希望你能避開各種危險,平平安安”。
    • “希望你幸福,安心自在”。
    • “希望你身體健康”。

關鍵點

  • 加利福尼亞大學洛杉磯分校(UCLA)實踐過這種方法。
  • “慈悲心”可以抑制DMN的過度活躍。

7.身體不適有痛感時——掃描全身法

目標與原因分析

  • 從大腦方面消除身體的疲勞與疼痛
  • 大腦的狀態會通過自律神經系統和激素反映到身體上。大腦積累太多疲勞后,身體的一部分會開始感到疲勞,嚴重時局部會感到疼痛。而正念冥想不僅能抑制短時間的疼痛,還能有效建立可應付疼痛的大腦結構

改善

  • 壓力性疼痛
  • 皮膚病、熱潮紅
  • 調節自律神經

步驟

  • ①平躺并關注自己的呼吸

    • 如果沒有平躺的環境,也可以坐在椅子上進行。
    • 有意識地關注呼吸時腹部的上下起伏變化。
  • ②將注意力集中在左腳尖

    • 腳接觸鞋子或襪子的觸感如何?
    • 腳趾與腳趾之間的觸感如何?
  • ③掃描全身

    • 從左腳尖開始“掃描”全身。
    • 吸氣時,設想空氣從鼻腔進入,經流全身后進入左腳尖。
    • 吐氣時,設想聚集在左腳尖的空氣,經流全身,從鼻腔呼出。
  • ④全身各個部位都可以這么做

    • 從左腳尖到左大腿的掃描結束后,可以從右腳、左手和右手、頭部及腹部等部位開始掃描全身。
    • 觀察有痛感的身體部位(比如痛感的強烈程度),并“掃描”這一部位。

關鍵點

  • 對于肩酸和全身乏力效果顯著。
  • 也要注意感受“身體的感覺是如何變化的”。

3.正念時刻 “高效休息法”的故事

提高注意力,擁有自制力

  • 提高注意力

    • 能夠持續關注同一事物
  • 提高情緒調節能力

    • 對壓力情緒等不再產生刺激性反應
  • 改變自我認知

    • 減少執念,增加自制力
  • 改變免疫力

    • 對病毒感染等產生免疫力,不易感冒

改善睡眠一邊睡覺一邊用“清潔劑”清洗大腦的疲勞物質

  • 就寢和起床的時間要固定(讓大腦記住生物鐘的節奏)
  • 避免攝取太多咖啡因等刺激性物質(交感神經一旦亢奮起來就容易睡不著)
  • 先把煩惱一一寫下來后再上床(煩惱會讓大腦無法獲得休息)
  • 早上起床之后要曬太陽(容易形成入睡和睡醒的節奏)
  • 適度運動( 適當的疲勞有助于睡眠)
  • 避免午睡時間過長(這樣會導致晚上的睡意降低,打亂睡眠節奏)
  • 避免在睡覺前進食(食物的消化活動會妨礙睡眠)
  • 不要在床上看電腦或手機(大腦會誤認為床不是睡覺的地方)
  • 一旦睡醒就立即下床(要讓大腦記住床是睡覺的地方)
  • 擁有一個為了入睡而自己特有的生活習慣,擁有儀式感(大腦最喜歡習慣)
  • 把臥室創造出一個可以放松的環境(副交感神經占據主位后會促進睡眠)

防止大腦疲勞的飲食

  • 最好每天都攝入的食物

    • 蔬菜、水果、堅果、豆類、薯類、全麥谷物、魚
      類、特級初榨橄欖油、芝士、酸奶
  • 建議適度攝取的食物

    • 雞肉、蛋
  • 盡量避免攝取的食物

    • 紅肉

讓大腦恢復活力的五個習慣

  • 擁有隨時切換開/關模式的儀式

    • 比如,決定聽完某首歌后開啟工作模式、洗完澡后開啟休息模式。務必通過特定的模式來嚴格區分工作模式和休息模式。
  • 接觸大自然

    • 通過接觸超越人類格局的非人工產物,把自己從日常生活和工作中解放出來
  • 接觸美好的事物

    • 美的感覺可以直接作用于大腦的獎勵系統和外側前額葉皮質
  • 培養自己埋頭做一件事情的能力

    • 專心致志做自己喜歡的事情會刺激大腦的獎勵系統
  • 回老家看看

    • 一般來說,成長的環境會讓人平靜,平靜是焦慮的對立面
  • 適度運動

    • 每周3~5次,混合有氧和力量訓練

只靠放松無法使“大腦休息”的理由

無論是個人還是一個組織,為了有所成長,單單靠拼命努力是遠遠不夠的。為了讓薪柴源源不斷地燃燒下去,需要讓薪柴之間留有空隙。這才是真正的休息。就像商業有商業的方法論一樣,休息也有休息的方法論

4.從Doing到Being

“任務導向型”的生活是一種一生都在不斷追求“要做些什么”的“Doing文化”。

而正念理論下的價值觀則更重視人生“要成為什么”的“Being文化”。對于已經厭倦不斷做事的美國人來說,這種思維方式顯然更具魅力。

5.美國精神科醫生推薦的五日簡單休息法

每天要做的事

  • 外出曬太陽。
  • 接觸森林、大海等自然環境(要像第一次看見那樣保持好奇心)。
  • 泡個舒服的熱水澡。
  • 做伸展運動或是瑜伽這種比較溫和的運動。
  • 不接觸數碼裝備,尤其是別上社交網絡。

前一天的準備——讓大腦進入休息模式

  • 準備一個切換模式的儀式:用新發型、固定的音樂或者香薰,為大腦建立一個條件反射機制,讓自己進入休息模式
  • 整理自己的日常生活:寫下平時遇到的壓力,然后放在平常不怎么使用的抽屜里
  • 將自己的房間整理成非日常生活的樣子:如果條件有限,可以想象自己住在林邊或者小溪邊

第一天——讓身體休息的偷懶日

  • 早上:睡到自然醒,起床后進行10分鐘左右的正念呼吸
  • 白天:只做最基本的家務,與此同時進行動態冥想
  • 晚上:泡個最舒服的熱水澡,泡澡的時候可以數數。記住別熬夜,睡眠要充足

第二天——逛逛附近沒有去過的地方

  • 早上:早點起床,沐浴在陽光下,呼吸戶外的空氣并進行動態冥想
  • 白天:去一些不太遠、你沒去過的地方。即使是去過的地方,試試走平常沒有走過的路。在走路或者騎車的同時,別忘了進行動態冥想

第三天——確認與他人之間的聯系

  • 早上:只要做10分鐘的正念呼吸即可
  • 白天:創造機會來確認自己和他人之間的聯系。最理想的方式是和朋友、家人一起愉快地用餐。另外,要有意識地表達對他人的感謝與愛意,比如寫信、送花、做志愿者等。也可以試著與老家的人或者從前的熟人聯絡一下。今天可是“半偷懶日”,注意自己是不是在不經意間用力過度了

第四天——釋放欲望的“狂野日”

  • 早上:做完10分鐘的正念呼吸之后,請認真感受自己的生理欲望和物質欲望。思考為什么會產生這種欲望,以及滿足這種欲望后會對個人和社會有何影響
  • 白天:滿足自己的欲望。事先預定好時間和金額后,盡情地購物或者吃美食吧
  • 晚上:這個時間,腦海中便會開始出現休息前的生活和工作了。此時可以通過冥想來保持內心的平靜,并在睡前練習一下感恩的“慈悲心”

第五天——為了下一次休息變得更好

  • 白天:這一天,一邊想想前四天“每天要做的事”,一邊悠閑地度過一整天。此時也許你會開始想起明天一如往常的生活,但是你已經連續五天實行了各種冥想,你應該對日常生活的看法有所改變了
  • 晚上:做一些從非日常生活過渡到日常生活的儀式。準備一個筆記本,規劃一下“下一次五天休息計劃”
作者:ThinkWon 發表于 2020/09/01 20:13:02 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/108349809
閱讀:4537
]]>
<![CDATA[[原]讀書清單-計算機]]> http://www.gifted-edu.com/ThinkWon/article/details/108077754 http://www.gifted-edu.com/ThinkWon/article/details/108077754 ThinkWon 2020/08/18 15:18:03

分類:編程語言與程序設計,辦公軟件,數據庫,圖形圖像,計算機安全,人工智能,操作系統,電子商務,網絡與通信,計算機理論、基礎知識,大數據與云計算,IT人文/互聯網

編程語言與程序設計

Java核心技術

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 Java編程思想(第4版) 編程語言與程序設計
2 Head First Java 中文版 第二版 涵蓋Java5.0 編程語言與程序設計
3 Effective Java中文版(原書第3版) 編程語言與程序設計
4 碼出高效:Java開發手冊 編程語言與程序設計
5 重構 改善既有代碼的設計 第2版 編程語言與程序設計
6 重構 改善既有代碼的設計 Java語言版 編程語言與程序設計
7 代碼整潔之道 編程語言與程序設計
8 代碼整潔之道 程序員的職業素養 編程語言與程序設計
9 Java程序員修煉之道 編程語言與程序設計
10 Java核心技術 卷I:基礎知識(原書第10版) 編程語言與程序設計
11 Java核心技術卷II:高級特性(原書第10版) 編程語言與程序設計
12 深入分析Java Web技術內幕(修訂版) 編程語言與程序設計
13 算法(第4版) 編程語言與程序設計
14 數據結構與算法分析:Java語言描述(原書第3版) 編程語言與程序設計
15 大型網站系統與Java中間件實踐 編程語言與程序設計

并發編程

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 Java并發編程的藝術 編程語言與程序設計
2 實戰Java高并發程序設計 編程語言與程序設計
3 Java并發編程實戰 編程語言與程序設計
4 Java核心技術系列:Java多線程編程核心技術 編程語言與程序設計

Java虛擬機

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 深入理解Java虛擬機:JVM高級特性與最佳實踐(第2版) 編程語言與程序設計
2 實戰Java虛擬機:JVM故障診斷與性能優化(第2版) 編程語言與程序設計
3 HotSpot實戰 編程語言與程序設計

Spring全家桶

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 expert one-on-one J2EE Development without EJB 編程語言與程序設計
2 Spring實戰 第4版 編程語言與程序設計
3 Spring源碼深度解析 第2版 編程語言與程序設計
4 精通Spring MVC 4 編程語言與程序設計
5 Spring微服務實戰 編程語言與程序設計
6 Spring Boot編程思想(核心篇) 編程語言與程序設計
7 JavaEE開發的顛覆者:Spring Boot實戰 編程語言與程序設計
8 Spring Boot 2精髓:從構建小系統到架構分布式大系統 編程語言與程序設計
9 Spring Cloud微服務實戰 編程語言與程序設計
10 深入理解Spring Cloud與微服務構建 編程語言與程序設計
11 Spring Cloud與Docker微服務架構實戰(第2版) 編程語言與程序設計
12 Spring Cloud與Docker高并發微服務架構設計實施 編程語言與程序設計

MyBatis與Hibernate

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 深入淺出MyBatis技術原理與實戰 編程語言與程序設計
2 Hibernate實戰(第2版) 編程語言與程序設計

C語言

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 C Primer Plus 第6版 中文版 編程語言與程序設計

Python

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 Python基礎教程(第3版) 編程語言與程序設計
2 Python編程 從入門到實踐 編程語言與程序設計
3 數據結構 Python語言描述 編程語言與程序設計
4 Python核心編程(第3版) 編程語言與程序設計
5 Python數據分析與挖掘實戰 編程語言與程序設計

前端

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 JavaScript高級程序設計(第3版) 編程語言與程序設計
2 鋒利的jQuery(第2版) 編程語言與程序設計
3 Vue.js實戰 編程語言與程序設計
4 深入淺出Vue.js 編程語言與程序設計

其他

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 RabbitMQ實戰指南 編程語言與程序設計
2 Netty實戰 編程語言與程序設計
3 深入理解Nginx:模塊開發與架構解析(第2版) 編程語言與程序設計
4 精通Nginx(第2版) 編程語言與程序設計
5 Tomcat架構解析 編程語言與程序設計
6 精通Git 第2版 編程語言與程序設計
7 ELK Stack權威指南(第2版) 編程語言與程序設計
8 Jenkins權威指南 編程語言與程序設計
9 Docker技術入門與實戰(第3版) 編程語言與程序設計
10 Kubernetes in Action中文版 編程語言與程序設計
11 Kubernetes權威指南:從Docker到Kubernetes實踐全接觸 編程語言與程序設計

數據庫

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 MySQL數據庫應用從入門到精通(附光盤) 數據庫
2 SQL即查即用(全彩版) 數據庫
3 MySQL技術內幕:InnoDB存儲引擎(第2版) 數據庫
4 高性能MYSQL 第3版 數據庫
5 Oracle Database 12c DBA官方手冊(第8版) 數據庫
6 Oracle Database 12c Oracle RMAN備份與恢復(第4版) 數據庫
7 Redis實戰 數據庫

操作系統

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 深入Linux內核架構 操作系統
2 深入理解LINUX內核(第3版) 操作系統
3 Linux命令行與shell腳本編程大全(第3版) 操作系統

網絡與通信

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 億級流量網站架構核心技術 跟開濤學搭建高可用高并發系統 網絡與通信
2 大型網站技術架構 核心原理與案例分析 網絡與通信
3 從Paxos到Zookeeper 分布式一致性原理與實踐 網絡與通信
4 RabbitMQ實戰:高效部署分布式消息隊列 網絡與通信
5 Nginx高性能Web服務器詳解 網絡與通信
6 漏洞 網絡與通信

人工智能

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 人工智能(第2版) 人工智能
2 人工智能簡史 人工智能
3 深度學習 人工智能
4 TensorFlow:實戰Google深度學習框架(第2版) 人工智能
5 TensorFlow實戰 人工智能
6 Python深度學習 人工智能
7 Python神經網絡編程 人工智能
8 機器學習 人工智能
9 機器學習實戰 人工智能
10 終極算法 機器學習和人工智能如何重塑世界 人工智能

大數據與云計算

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 大數據架構詳解:從數據獲取到深度學習 大數據與云計算
2 Hadoop權威指南:大數據的存儲與分析(第4版) 大數據與云計算
3 Docker 容器與容器云(第2版) 大數據與云計算

辦公軟件

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 WORD之光:顛覆認知的WORD必修課 辦公軟件
2 EXCEL之光 高效工作的EXCEL 辦公軟件
3 PPT之光 三個維度打造完美PPT 辦公軟件

計算機理論、基礎知識

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 數學之美(第二版) 計算機理論、基礎知識

電子商務

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 數據化管理:洞悉零售及電子商務運營 電子商務

IT人文/互聯網

序號 書名 分類 是否已買 是否已讀 是否整理讀書筆記
1 企業IT架構轉型之道 阿里巴巴中臺戰略思想與架構實戰 IT人文/互聯網
作者:ThinkWon 發表于 2020/08/18 15:18:03 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/108077754
閱讀:6612 評論:5 查看評論
]]>
<![CDATA[[原]Swagger2常用注解說明]]> http://www.gifted-edu.com/ThinkWon/article/details/107477801 http://www.gifted-edu.com/ThinkWon/article/details/107477801 ThinkWon 2020/07/20 23:40:14

Swagger2簡介

swagger官網 對 swagger 的描述如下:

Swagger takes the manual work out of API documentation, with a range of solutions for generating, visualizing, and maintaining API docs.

Simplify API development for users, teams, and enterprises with the Swagger open source and professional toolset.

Swagger提供了用于生成,可視化和維護API文檔的一系列解決方案,從而使API文檔不再需要人工操作。

借助Swagger開源和專業工具集,為用戶,團隊和企業簡化API開發。

我的總結:Swagger 是一套基于 OpenAPI 規范構建的開源工具,可以幫助我們設計、構建、使用和測試 Rest API。

使用Swagger解決的問題

現在大部分公司都采用前后端分離開發的模式,前端和后端工程師各司其職。這就要求有一份及時更新且完整的Rest API 文檔來提高工作效率。Swagger 解決的問題主要有以下三點:

  1. 保證文檔的時效性:只需要少量的注解,Swagger 就可以根據代碼自動生成 API 文檔,代碼變文檔跟著變
  2. 接口請求參數和返回結果不明確的問題
  3. 在線測試接口

Spring Boot集成Swagger2

這里通過構建一個簡單的Spring Boot項目,并使用Swagger注解,來演示如何使用Swagger

添加依賴

這里沒有添加springfox-swagger2和springfox-swagger2-ui依賴,而是使用knife4j-spring-boot-starter依賴,官網地址:https://doc.xiaominfo.com/knife4j/

<!-- 一些校驗的依賴,不然啟動會報NoClassDefFoundError: javax/validation/constraints/Min -->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

<!-- Spring Boot單服務架構使用最新版的knife4j依賴,已經繼承swagger依賴,同時增強UI實現 -->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>2.0.3</version>
</dependency>

<!-- lombok依賴 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

<!-- spring-boot-starter-web依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

添加Swagger2Config配置類

注意:RequestHandlerSelectors.basePackage("com.jourwon.springboot.knife4j.controller") 為 Controller 包路徑,不然生成的文檔掃描不到接口,也可以使用RequestHandlerSelectors.any()配置

/**
 * Swagger2配置類
 *
 * @author JourWon
 * @date 2020/6/1
 */
@EnableKnife4j
@EnableSwagger2
@Configuration
@Import(value = {BeanValidatorPluginsConfiguration.class})
public class Swagger2Config {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                // 標題
                .title("我的Swagger API文檔")
                // 描述
                .description("使用Knife4j構建API文檔")
                // 作者信息
                .contact(new Contact("ThinkWon", "https://thinkwon.www.gifted-edu.com/", "thinkwon@163.com"))
                // 服務網址
                .termsOfServiceUrl("https://thinkwon.www.gifted-edu.com/")
                // 版本
                .version("1.0.0")
                .build();
    }

}

編寫接口

用戶DTO

/**
 * 用戶
 *
 * @author JourWon
 * @date 2020/6/1
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "用戶", description = "查詢用戶")
public class UserDTO implements Serializable {

    private static final long serialVersionUID = 78806598597025327L;

    @ApiModelProperty(value = "用戶id")
    private Integer userId;

    @ApiModelProperty(value = "用戶名")
    private String username;

}

用戶controller


/**
 * 用戶controller
 *
 * @author JourWon
 * @date 2020/6/1
 */
@RestController
@RequestMapping(value = {"/user"})
@Api(tags = {"用戶controller"})
public class UserController {

    private List<UserDTO> list = new ArrayList<>();

    @PostConstruct
    private void post() {
        list.add(new UserDTO(1, "JourWon"));
        list.add(new UserDTO(2, "Jobs"));
        list.add(new UserDTO(3, "JackMa"));
    }

    @GetMapping("/list")
    @ApiOperation(value = "查詢用戶列表")
    public List<UserDTO> list() {
        return list;
    }

    @GetMapping("/page")
    @ApiOperation(value = "分頁查詢用戶列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "當前頁數"),
            @ApiImplicitParam(name = "pageSize", value = "每頁記錄數")
    })
    public List<UserDTO> page(
            @RequestParam(defaultValue = "1", required = false) Integer pageNum, @RequestParam(defaultValue = "10", required = false) Integer pageSize) {
        return list;
    }

    @GetMapping("/{userId}")
    @ApiOperation(value = "根據用戶id查詢用戶")
    public UserDTO get(@PathVariable("userId") Integer userId) {
        for (UserDTO userDTO : list) {
            if (userDTO.getUserId().equals(userId)) {
                return userDTO;
            }
        }
        return new UserDTO();
    }

    @PostMapping
    @ApiOperation(value = "新增用戶")
    public Boolean insert(@RequestBody @ApiParam(name = "UserDTO", value = "新增用戶參數") UserDTO userDTO) {
        list.add(userDTO);
        return true;
    }

    @DeleteMapping("/{userId}")
    @ApiOperation(value = "根據用戶id刪除用戶")
    public Boolean delete(@PathVariable("userId") Integer userId) {
        Iterator<UserDTO> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().getUserId().equals(userId)) {
                iterator.remove();
                return true;
            }
        }
        return false;
    }

    @PutMapping
    @ApiOperation(value = "更新用戶信息")
    @ApiResponses({
            @ApiResponse(code = 400, message = "請求參數沒填好"),
            @ApiResponse(code = 404, message = "請求路徑沒有或頁面跳轉路徑不對")
    })
    public Boolean update(@RequestBody @ApiParam(name = "UserDTO", value = "更新用戶參數") UserDTO userDTO) {
        Iterator<UserDTO> iterator = list.iterator();
        while (iterator.hasNext()) {
            UserDTO next = iterator.next();
            if (next.getUserId().equals(userDTO.getUserId())) {
                next.setUsername(userDTO.getUsername());
                return true;
            }
        }
        return false;
    }

}

這個controller有了六個接口,分別是:

  1. /user/list,get請求方式:查詢用戶列表
  2. /user/page,get請求方式:分頁查詢用戶列表
  3. /user/{userId},get請求方式:根據用戶id查詢用戶
  4. /user,post請求方式:新增用戶
  5. /user,put請求方式:更新用戶信息
  6. /user/{userId},delete請求方式:根據用戶id刪除用戶

訪問接口文檔

啟動一下項目,然后在瀏覽器中訪問 http://localhost:8080/doc.html

主頁展示API文檔基本信息,包括簡介,作者,版本等信息

在這里插入圖片描述

同時可以看到用戶controller的所有接口

在這里插入圖片描述

這里我們調試以下查詢用戶列表的接口

在這里插入圖片描述

至此,Spring Boot集成Swagger2,構建API文檔已經完成

Swagger2常用注解說明

Controller相關注解

@Api

用在請求的類上,表示對類的說明

注解屬性 類型 描述
tags String[] 描述請求類的作用,非空時會覆蓋value的值
value String 描述請求類的作用
非常用參數
produces String 設置 MIME 類型列表(output),例:“application/json, application/xml”,默認為空
consumes String 設置 MIME 類型列表(input),例:“application/json, application/xml”,默認為空
protocols String 設置特定協議,例:http, https, ws, wss
authorizations Authorization[] 獲取授權列表(安全聲明),如果未設置,則返回一個空的授權值
hidden boolean 默認為 false,配置為 true 將在文檔中隱藏
description String 對 api 資源的描述,在 1.5 版本后不再支持
basePath String 基本路徑可以不配置,在 1.5 版本后不再支持
position int 如果配置多個 Api 想改變顯示的順序位置,在 1.5 版本后不再支持

示例

@Api(tags = {"用戶controller"})
public class UserController {}

接口相關注解

@ApiOperation

用在請求類的方法上,說明方法的用途和作用

注解屬性 類型 描述
value String 方法的簡要說明
notes String 方法的備注說明
非常用參數
tags String[] 操作標簽,非空時將覆蓋value的值
response Class<?> 響應類型(即返回對象)
responseContainer String 聲明包裝的響應容器(返回對象類型)。有效值為 “List”, “Set” or “Map”
responseReference String 指定對響應類型的引用。將覆蓋任何指定的response()類
httpMethod String 指定HTTP方法,“GET”, “HEAD”, “POST”, “PUT”, “DELETE”, “OPTIONS” and “PATCH”
position int 如果配置多個 Api 想改變顯示的順序位置,在 1.5 版本后不再支持
nickname String 第三方工具唯一標識,默認為空
responseHeaders ResponseHeader[] 響應頭列表
code int 響應的HTTP狀態代碼。默認 200
extensions Extension[] 擴展屬性列表數組
produces String 設置 MIME 類型列表(output),例:“application/json, application/xml”,默認為空
consumes String 設置 MIME 類型列表(input),例:“application/json, application/xml”,默認為空
protocols String 設置特定協議,例:http, https, ws, wss
authorizations Authorization[] 獲取授權列表(安全聲明),如果未設置,則返回一個空的授權值
hidden boolean 默認為 false,配置為 true 將在文檔中隱藏

示例

@GetMapping("/list")
@ApiOperation(value = "查詢用戶列表")
public List<UserDTO> list() {
    return list;
}

@ApiParam

可用在方法,參數和字段上,一般用在請求體參數上,描述請求體信息

注解屬性 類型 描述
name String 參數名稱,參數名稱可以覆蓋方法參數名稱,路徑參數必須與方法參數一致
value String 參數的簡要說明
required boolean 參數是否必須傳,默認為 false (路徑參數必填)
defaultValue String 參數的默認值
非常用參數
allowableValues String 限制參數的可接受值。1.以逗號分隔的列表 2.范圍值 3.設置最小值/最大值
access String 允許從API文檔中過濾參數
allowMultiple boolean 指定參數是否可以通過具有多個事件接受多個值,默認為 false
example String 單個示例
examples Example 參數示例。僅適用于 BodyParameters
hidden boolean 默認為 false,配置為 true 將在文檔中隱藏
@PostMapping
@ApiOperation(value = "新增用戶")
public Boolean insert(@RequestBody @ApiParam(name = "UserDTO", value = "新增用戶參數") UserDTO userDTO) {
    list.add(userDTO);
    return true;
}

@ApiImplicitParams

用在請求的方法上,表示一組參數說明,里面是@ApiImplicitParam列表

@ApiImplicitParam

用在 @ApiImplicitParams 注解中,一個請求參數的說明

注解屬性 類型 描述
name String 參數名稱,參數名稱可以覆蓋方法參數名稱,路徑參數必須與方法參數一致
value String 參數的說明、解釋
required boolean 參數是否必須傳,默認為 false (路徑參數必填)
paramType String 參數的位置,header 請求參數的獲取:@RequestHeader;query 請求參數的獲取:@RequestParam;path(用于 restful 接口)–> 請求參數的獲取:@PathVariable;body(不常用);form(不常用)
dataType String 參數類型,默認 String,其它值 dataType=“Integer”
defaultValue String 參數的默認值
非常用參數
allowableValues String 限制參數的可接受值。1.以逗號分隔的列表 2.范圍值 3.設置最小值/最大值
access String 允許從API文檔中過濾參數
allowMultiple boolean 指定參數是否可以通過具有多個事件接受多個值,默認為 false
example String 單個示例
examples Example 參數示例。僅適用于 BodyParameters
@GetMapping("/page")
@ApiOperation(value = "分頁查詢問題列表")
@ApiImplicitParams({
    @ApiImplicitParam(name = "pageNum", value = "當前頁數"),
    @ApiImplicitParam(name = "pageSize", value = "每頁記錄數")
})
public List<UserDTO> page(
    @RequestParam(defaultValue = "1", required = false) Integer pageNum, @RequestParam(defaultValue = "10", required = false) Integer pageSize) {
    return list;
}

@ApiResponses

用在請求的方法上,表示一組響應

@ApiResponse

用在 @ApiResponses 中,一般用于表達一個錯誤的響應信息

注解屬性 類型 描述
code int 響應狀態碼
message String 信息,例如 “請求參數沒填好”
response Class<?> 拋出異常的類

示例

@PutMapping
@ApiOperation(value = "更新用戶信息")
@ApiResponses({
    @ApiResponse(code = 400, message = "請求參數沒填好"),
    @ApiResponse(code = 404, message = "請求路徑沒有或頁面跳轉路徑不對")
})
public Boolean update(@RequestBody @ApiParam(name = "UserDTO", value = "更新用戶參數") UserDTO userDTO) {}

Model相關注解

@ApiModel

用在實體類(模型)上,表示相關實體的描述。

注解屬性 類型 描述
value String 模型的備用名稱
description String 該類的詳細說明

示例

@ApiModel(value = "用戶", description = "查詢用戶")
public class UserDTO implements Serializable

@ApiModelProperty

用在實體類屬性上,表示屬性的相關描述。

注解屬性 類型 描述
value String 屬性簡要描述
name String 重寫屬性名稱
dataType Stirng 重寫屬性類型
required boolean 參數是否必傳,默認為 false
example Stirng 屬性示例
非常用參數
hidden boolean 是否在文檔中隱藏該屬性,默認false
allowEmptyValue boolean 是否允許為空,默認false
allowableValues String 限制參數的可接受值。1.以逗號分隔的列表 2.范圍值 3.設置最小值/最大值
readOnly boolean 將屬性設定為只讀,默認false
reference String 指定對相應類型定義的引用,覆蓋指定的任何參數值

示例

@ApiModelProperty(value = "用戶id")
private Integer userId;

@ApiModelProperty(value = "用戶名")
private String username;
作者:ThinkWon 發表于 2020/07/20 23:40:14 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/107477801
閱讀:10983 評論:5 查看評論
]]>
<![CDATA[[原]Docker 從入門到實踐系列一 - 什么是Docker]]> http://www.gifted-edu.com/ThinkWon/article/details/107477065 http://www.gifted-edu.com/ThinkWon/article/details/107477065 ThinkWon 2020/07/20 23:13:22


img

虛擬機和容器

虛擬機和容器都屬于虛擬化技術。

虛擬機是在一套硬件上,虛擬出一個完整的操作系統,在該系統上再運行所需的應用進程。

容器不是虛擬出一個完整的操作系統,而是對進程的隔離。

下面的圖片比較了 Docker 和虛擬機的不同之處,可見容器是在操作系統層面上實現虛擬化,直接復用本地主機的操作系統,而虛擬機則是在硬件層面實現。

虛擬機

Docker

虛擬機和容器的區別

特性 虛擬機 容器
量級 重量級 輕量級
性能 接近原生 弱于原生
操作系統 每個VM都在自己的OS中運行 所有容器共享主機操作系統
啟動時間 以分鐘為單位 以毫秒為單位
硬盤使用 一般為 GB 一般為 MB
占用資源 占用更多的內存和CPU資源 占用較少的內存和CPU資源
隔離性 完全隔離,因此更安全 進程級隔離,可能不太安全
系統支持量 一般幾十個 支持上千個容器

什么是 Docker

Docker 是開源應用容器引擎,輕量級容器技術。Docker 誕生于 2013 年初,最初是 dotCloud 公司內部的一個業余項目。它基于 Google 公司推出的 Go 語言實現。 項目后來加入了 Linux 基金會,遵從了 Apache 2.0 協議,項目代碼在 GitHub 上進行維護。

Docker 自開源后受到廣泛的關注和討論,以至于 dotCloud 公司后來都改名為 Docker Inc。Redhat 已經在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 產品中廣泛應用。

Docker 項目的目標是實現輕量級的操作系統虛擬化解決方案。 Docker 的基礎是 Linux 容器(LXC)等技術。

在 LXC 的基礎上 Docker 進行了進一步的封裝,讓用戶不需要去關心容器的管理,使得操作更為簡便。用戶操作 Docker 的容器就像操作一個快速輕量級的虛擬機一樣簡單。

Docker 的優點

作為一種新興的虛擬化技術,Docker 跟傳統的虛擬機相比具有眾多的優勢。

  • 一致的運行環境:Docker 的鏡像提供了除內核外完整的運行時環境,確保了應用運行環境的一致性,從而不會再出現“這段代碼在我機器上沒問題啊”這類問題。
  • 更快速的啟動時間:可以做到秒級、甚至毫秒級的啟動時間。大大的節約了開發、測試、部署的時間。
  • 隔離性:避免公用的服務器,資源會容易受到其他用戶的影響。
  • 彈性伸縮,快速擴展:善于處理集中爆發的服務器使用壓力。
  • 更輕松的遷移:Docker 容器幾乎可以在任意的平臺上運行,包括物理機、虛擬機、公有云、私有云、個人電腦、服務器等。 這種兼容性可以讓用戶把一個應用程序從一個平臺直接遷移到另外一個。
  • 持續交付和部署:使用Docker可以通過定制應用鏡像來實現持續集成、持續交付、部署。

Docker 的應用場景

不同公司的應用場景不同,常見的應用場景有

  • Web 應用的自動化打包,自動化測試和持續集成、快速部署。
  • 彈性的云服務:因為 Docker 容器可以隨開隨關,很適合動態擴容和縮容。
  • 提供一致性的環境:同步開發環境和生產環境等

其他的應用場景可以參考:8 個 Docker 真實應用場景

Docker 核心概念

Docker 包括三個基本概念

  • 鏡像(Image)
  • 容器(Container)
  • 倉庫(Repository)

理解了這三個概念,就理解了 Docker 的整個生命周期。

Docker 三個關鍵動作:Build、Ship、 Run。

  • Build(構建鏡像):鏡像就像是集裝箱包括文件以及運行環境等資源
  • Ship(運輸鏡像):主機和倉庫間運輸,這里的倉庫就像是超級碼頭一樣
  • Run (運行鏡像):正在運行的鏡像就是一個容器,容器就是運行程序的地方

以上內容部分引自:《Docker 技術入門與實戰》

docker 鏡像(image)

  • 一個只讀模板,可以用來創建容器,一個鏡像可以創建多個容器
  • Docker 提供了一個很簡單的機制來創建和更新現有的鏡像,甚至可以直接從其他人那里獲取做好的鏡像直接使用

docker 容器(container)

  • 容器是從鏡像創建的運行實例,也就是鏡像啟動后的一個實例稱為容器,是獨立運行的一個或一組應用。
  • docker 利用容器來運行應用,他可以被啟動、開始、停止、刪除,每個容器都是相互隔離的、保證安全的平臺。
  • 可以把容器看做是一個簡易版的 Linux(包括 root 用戶權限、進程空間、用戶空間和網絡空間等)和運行在其中的應用程序。

注:鏡像是只讀的,容器在啟動的時候創建一層可寫層作為最上層。

docker 倉庫(resoisitory)

倉庫是集中存放鏡像文件的場所。有時候會把倉庫和倉庫注冊服務器(Registry)混為一談,并不嚴格區分。實際上,倉庫注冊服務器上往往存放著多個倉庫,每個倉庫中又包含了多個鏡像,每個鏡像有不同的標簽(tag)。

倉庫分為公開倉庫(Public)和私有倉庫(Private)兩種形式。

最大的公開倉庫是 Docker Hub,存放了數量龐大的鏡像供用戶下載。 國內的公開倉庫包括 Docker Pool 等,可以提供大陸用戶更穩定快速的訪問。

當然,用戶也可以在本地網絡內創建一個私有倉庫。

當用戶創建了自己的鏡像之后就可以使用 push 命令將它上傳到公有或者私有倉庫,這樣下次在另外一臺機器上使用這個鏡像時候,只需要從倉庫上 pull 下來就可以了。

注:Docker 倉庫的概念跟 Git 類似,注冊服務器可以理解為 GitHub 這樣的托管服務。

底層原理

底層原理

docker 底層使用了一些 linux 內核的特性,大概有 namespacecgroupsufs

namespace

docker 使用 linux namespace 構建隔離的環境,它由以下 namespace 組成

  • pid:隔離進程
  • net:隔離網絡
  • ipc:隔離 IPC
  • mnt:隔離文件系統掛載
  • uts:隔離hostname
  • user: 隔離uid/gid

control groups

也叫 cgroups,限制資源配額,比如某個容器只能使用 100M 內存

union file systems

UnionFS 是一種分層、輕量級并且高性能的文件系統,支持對文件系統的修改作為一次提交來一層層的疊加。docker 的鏡像與容器就是分層存儲,可用的存儲引擎有 aufsoverlay 等。

docker 的鏡像和容器都使用了 unionFS 做分層存儲,鏡像作為只讀層是共享的,而容器在鏡像之上附加了一層可寫層,最大程度地減少了空間的浪費。

關于分層存儲的詳細內容可以查看官方文檔 docker: About storage drivers

Docker 引擎

Docker 引擎是一個 Client-Server 應用程序,有以下主要組件:

  1. Server 是一個長期運行的程序,成為守護進程(Docker 命令)
  2. REST API,可以用來與守護進程進行通信并指示其操作的接口
  3. 命令行界面(CLI)客戶端(Docker 命令)

在這里插入圖片描述

命令行界面使用 API 通過腳本或直接在命令行界面通過命令與 Docker 守護進程交互。

Docker 架構

docker 的架構圖如下

在這里插入圖片描述

從圖中可以看出幾個組成部分

  • docker client:即 docker 命令行工具
  • docker host:宿主機,docker daemon 的運行環境服務器
  • docker daemondocker 的守護進程,docker client 通過命令行與 docker daemon 交互
  • container:最小型的一個操作系統環境,可以對各種服務以及應用容器化
  • image:鏡像,可以理解為一個容器的模板配置,通過一個鏡像可以啟動多個容器
  • registry:鏡像倉庫,存儲大量鏡像,可以從鏡像倉庫拉取和推送鏡像

Docker 為什么快

這里我們說下 Docker 為什么比 VMware 快。

  1. 首先 Docker 的抽象層比 VMware 虛擬機少。Docker 不需要 Hypervisor 實現硬件資源的虛擬化,Docker 需要的硬件都是實際物理機上的硬件資源。所以在磁盤占用、CPU、內存利用率上 Docker 有很大的優勢。
  2. Docker 利用的是宿主機的內核,不需要 Guest OS。當新建一個容器時,Docker 不需要像虛擬機一樣重新加載一個操作系統內核,這樣就減少了加載操作系統內核這樣的費時費資源過程。因 Docker 使用宿主機的操作系統,新建一個 Docker 容器只需幾秒。

在這里插入圖片描述

作者:ThinkWon 發表于 2020/07/20 23:13:22 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/107477065
閱讀:11949
]]>
<![CDATA[[譯]虛擬機和容器有什么不同]]> http://www.gifted-edu.com/ThinkWon/article/details/107476886 http://www.gifted-edu.com/ThinkWon/article/details/107476886 ThinkWon 2020/07/20 23:00:06

虛擬機和容器都可以充分利用計算機硬件和軟件資源。容器是新興的事物,但是虛擬機已經并且繼續在各種規模的數據中心大受歡迎。

如果您正在尋找在云中運行自己的服務的最佳解決方案,則需要了解這些虛擬化技術,了解它們之間的區別以及每種技術的最佳用途是什么。

什么是虛擬機?

虛擬機(VM)是計算機系統的仿真。簡而言之,它可以在一臺計算機的硬件上運行看似多臺單獨的計算機。

操作系統(OS)及其應用程序共享單個主機服務器或主機服務器池的硬件資源。每個VM都需要自己的基礎OS,并且硬件已虛擬化。系統管理程序或虛擬機監視器(Hypervisor)是創建和運行VM的軟件。它位于硬件和虛擬機之間,是虛擬化服務器所必需的。

由于虛擬化技術和云服務的出現,IT部門可以采用虛擬機(VM)作為降低成本和提高效率的一種方式。

虛擬機系統架構圖

但是,VM會占用大量系統資源。每個VM不僅運行操作系統的完整副本,還需要運行操作系統所需的硬件虛擬副本。這大量消耗RAM和CPU資源。與運行單獨的計算機相比,這仍然是經濟的,但是對于某些應用程序來說,它可能會過大,這時候就需要容器。

虛擬機的好處

  • 所有的操作系統資源
  • 已有的管理工具
  • 已有的安全工具
  • 眾所周知的安全控制

受歡迎的虛擬機提供商

什么是容器?

使用容器,可以像虛擬機(VM)一樣虛擬化基礎計算機,而無需虛擬化OS。

容器位于物理服務器及其主機操作系統(通常為Linux或Windows)的頂部。每個容器共享主機OS內核,通常也共享二進制文件和庫。共享組件是只讀的。共享操作系統資源(例如庫)可以大大減少重現操作系統代碼的需求,并且意味著服務器可以通過安裝單個操作系統來運行多個工作負載。因此,容器非常輕便-它們只有幾兆字節大小,只需幾秒鐘即可啟動。與容器相比,VM運行需要幾分鐘,并且比等效容器大一個數量級。

與VM相比,容器需要操作系統,支持程序和庫以及用于運行特定程序的系統資源。這意味著在單個服務器上放置容器的應用程序的數量是在VM上的兩倍至三倍。此外,使用容器,您可以為開發,測試和部署創建一個可移植的,一致的操作環境

集裝箱系統架構圖

容器種類

Linux容器(LXC) — 最初的Linux容器技術是Linux容器,通常稱為LXC。LXC是Linux操作系統級別的虛擬化方法,用于在單個主機上運行多個隔離的Linux系統。

Docker — Docker起初是一個構建單一應用程序LXC容器的項目,它對LXC進行了多次改造,使容器更加便攜和靈活使用。后來它變成了自己的容器運行環境。從較高的層次上講,Docker是一個Linux實用程序,可以有效地創建,運送和運行容器。

集裝箱的好處

  • 減少IT管理資源
  • 減少快照的大小
  • 更快地部署應用程序
  • 減少和簡化安全更新
  • 更少的代碼來傳輸,遷移和上傳工作負載

受歡迎的集裝箱供應商

虛擬機使用與容器使用

容器和VM都有優點和缺點,最終的決定取決于您的特定需求,但是有一些通用的經驗法則。

  • 當您需要在服務器上運行多個應用程序或需要管理多種操作系統時,VM是運行需要所有操作系統資源和應用程序的更好選擇。
  • 當您的首要任務是在最少數量的服務器上最大化運行的應用程序數量時,容器是一個更好的選擇。

虛擬機與容器有什么不同

虛擬機 容器
重量級 輕量級
性能有限 本機性能
每個VM都在自己的OS中運行 所有容器共享主機操作系統
硬件級虛擬化 操作系統虛擬化
啟動時間(以分鐘為單位) 啟動時間(以毫秒為單位)
分配所需的內存 需要更少的內存空間
完全隔離,因此更安全 進程級隔離,可能不太安全

對于大多數人來說,能夠同時包含這兩者是最理想的。在當前的虛擬化技術下,VM的靈活性和容器的輕量共同作用,以提供具有最大功能的環境。

如果您的組織正在運行同一操作系統的大量實例,則應研究容器是否合適。它們可能會為您節省大量的時間和金錢。

作者:ThinkWon 發表于 2020/07/20 23:00:06 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/107476886
閱讀:4802
]]>
<![CDATA[[原]MySQL中count(字段) ,count(主鍵 id) ,count(1)和count(*)的區別]]> http://www.gifted-edu.com/ThinkWon/article/details/106610859 http://www.gifted-edu.com/ThinkWon/article/details/106610859 ThinkWon 2020/06/08 00:48:17

注:下面的討論和結論是基于 InnoDB 引擎的。

首先要弄清楚 count() 的語義。count() 是一個聚合函數,對于返回的結果集,一行行地判斷,如果 count 函數的參數不是 NULL,累計值就加 1,否則不加。最后返回累計值。

所以,count(*)、count(1)和count(主鍵 id) 都表示返回滿足條件的結果集的總行數;而 count(字段),則表示返回滿足條件的數據行里面,參數“字段”不為 NULL 的總個數。

至于分析性能差別的時候,記住這么幾個原則:

  • server 層要什么就給什么;
  • InnoDB 只給必要的值;
  • 現在的優化器只優化了 count(*) 的語義為“取行數”,其他“顯而易見”的優化并沒有做。

count(可空字段)

掃描全表,讀到server層,判斷字段可空,拿出該字段所有值,判斷每一個值是否為空,不為空則累加

count(非空字段)與count(主鍵 id)

掃描全表,讀到server層,判斷字段不可空,按行累加。

count(1)

掃描全表,但不取值,server層收到的每一行都是1,判斷不可能是null,按值累加。

注意:count(1)執行速度比count(主鍵 id)快的原因:從引擎返回 id 會涉及到解析數據行,以及拷貝字段值的操作。

count(*)

MySQL 執行count(*)在優化器做了專門優化。因為count(*)返回的行一定不是空。掃描全表,但是不取值,按行累加。

看到這里,你會說優化器就不能自己判斷一下嗎,主鍵 id 肯定是非空的,為什么不能按照 count(*) 來處理,多么簡單的優化。當然 MySQL 專門針對這個語句進行優化也不是不可以。但是這種需要專門優化的情況太多了,而且 MySQL 已經優化過 count(*) 了,你直接使用這種語句就可以了。

性能對比結論

count(可空字段) < count(非空字段) = count(主鍵 id) < count(1) ≈ count(*)

作者:ThinkWon 發表于 2020/06/08 00:48:17 原文鏈接 http://www.gifted-edu.com/ThinkWon/article/details/106610859
閱讀:13003 評論:2 查看評論
]]>
多乐彩