Chúng ta sẽ gặp một đối tượng mới: Date . Nó lưu trữ ngày, giờ và cung cấp các phương thức để quản lý ngày / giờ.

Chẳng hạn, chúng ta có thể sử dụng nó để lưu trữ thời gian tạo / sửa đổi, để đo thời gian hoặc chỉ để in ra ngày hiện tại.

1. Khởi tạo date

Để tạo một Date bằng cách gọi đối tượng new Date()với một trong các đối số sau:new Date()

Không có đối số – tạo một đối tượng Date cho ngày và giờ hiện tại:

let now = new Date();
alert( now ); // shows current date/time

new Date(milliseconds)

Tạo một Dateđối tượng với thời gian bằng số mili giây (1/1000 giây) được truyền sau ngày 1 tháng 1 năm 1970 UTC + 0.

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

// 0 means 01.01.1970 UTC+0
let Jan01_1970 = new Date(0);
alert( Jan01_1970 );

// now add 24 hours, get 02.01.1970 UTC+0
let Jan02_1970 = new Date(24 * 3600 * 1000);
alert( Jan02_1970 );

Một số nguyên biểu thị số mili giây đã trôi qua kể từ đầu năm 1970 được gọi là dấu thời gian(timestamp).

Đó là một đại diện số của một ngày. Chúng ta luôn có thể tạo một ngày từ dấu thời gian(timestamp) bằng cách sử dụng new Date(timestamp)và chuyển đổi đối tượngDatehiện có sang dấu thời gian bằng phương thức date.getTime() (xem bên dưới).

Ngày trước ngày 01.01.1970 có dấu thời gian(timestamp) âm, ví dụ:

// 31 Dec 1969
let Dec31_1969 = new Date(-24 * 3600 * 1000);
alert( Dec31_1969 );

new Date(datestring)

Nếu có một đối số duy nhất và đó là một chuỗi, thì nó sẽ được phân tích cú pháp tự động. Thuật toán giống như sử dụng Date.parse, chúng ta sẽ đề cập sau.

let date = new Date("2017-01-26");
alert(date);
// The time is not set, so it's assumed to be midnight GMT and
// is adjusted according to the timezone the code is run in
// So the result could be
// Thu Jan 26 2017 11:00:00 GMT+1100 (Australian Eastern Daylight Time)
// or
// Wed Jan 25 2017 16:00:00 GMT-0800 (Pacific Standard Time)

new Date(year, month, date, hours, minutes, seconds, ms)

Tạo ngày với các thành phần nhất định trong múi giờ địa phương. Chỉ có hai đối số đầu tiên là bắt buộc.

  • Các yearphải có 4 chữ số: 2013không quan trọng, không phải là 98.
  • Số monthbắt đầu bằng 0(tháng 1), tối đa 11(tháng 12).
  • Các tham số date thực sự là ngày của tháng, nếu vắng mặt thì 1được giả định là mặc định.
  • Nếu hours/minutes/seconds/msvắng mặt, thì chúng được coi là bằng 0.

Ví dụ:

new Date(2011, 0, 1, 0, 0, 0, 0); // 1 Jan 2011, 00:00:00
new Date(2011, 0, 1); // the same, hours etc are 0 by default

Độ chính xác tối thiểu là 1 ms (1/1000 giây):

let date = new Date(2011, 0, 1, 2, 3, 4, 567);
alert( date ); // 1.01.2011, 02:03:04.567

2. Truy cập các thành phần của date

Có các phương thức để truy cập năm, tháng, v.v. từ đối tượngDate:

getFullYear() Lấy ra năm (4 chữ số)

getMonth() lấy ra tháng, từ 0 đến 11 .

getDate() Lấy ra ngày trong tháng, từ 1 đến 31, tên của phương thức trông hơi lạ.

getHgetHours(), getMinutes(), getSeconds(), getMilliseconds() Lấy ra các thành phần thời gian tương ứng.

Không có getYear(), nhưng cógetFullYear()

Nhiều công cụ JavaScript thực hiện một phương thức không chuẩn getYear(). Phương thức này không được chấp nhận. Nó trả về năm đôi khi có 2 chữ số. Xin đừng bao giờ sử dụng nó. Nên dùng getFullYear()để lấy năm.

Ngoài ra, chúng ta có thể nhận được một ngày trong tuần:

getDay() Lấy ngày trong tuần, từ 0(Chủ nhật) đến 6(Thứ bảy). Ngày đầu tiên luôn là Chủ nhật, ở một số quốc gia không như vậy, nhưng không thể thay đổi.

Tất cả các phương thức trên trả về các thành phần liên quan đến múi giờ địa phương.

Ngoài ra còn có các múi giờ UTC, trở lại ngày, tháng, năm, v.v. theo múi giờ UTC + 0: getUTCFullYear(), getUTCMonth(), getUTCDay(). Chỉ cần chèn "UTC"ngay sau đó "get".

Nếu múi giờ địa phương của bạn bị thay đổi so với UTC, thì code bên dưới hiển thị các múi giờ khác nhau:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

// current date
let date = new Date();

// the hour in your current time zone
alert( date.getHours() );

// the hour in UTC+0 time zone (London time without daylight savings)
alert( date.getUTCHours() );

Bên cạnh các phương thức đã cho, có hai phương thức đặc biệt không có biến thể UTC:

getTime()

Trả về dấu thời gian cho ngày – một số mili giây được truyền từ ngày 1 tháng 1 năm 1970 UTC + 0.

getTimezoneOffset()

Trả về sự khác biệt giữa UTC và múi giờ địa phương, tính bằng phút:

// if you are in timezone UTC-1, outputs 60
// if you are in timezone UTC+3, outputs -180
alert( new Date().getTimezoneOffset() );

3. Cài đặt các thành phần date

Các phương thức sau đây cho phép đặt các thành phần ngày / giờ:

setFullYear(year, [month], [date])
setMonth(month, [date])
setDate(date)
setHours(hour, [min], [sec], [ms])
setMinutes(min, [sec], [ms])
setSeconds(sec, [ms])
setMilliseconds(ms)
setTime(milliseconds)(đặt toàn bộ ngày theo mili giây kể từ ngày 01.01.1970 UTC)

Mỗi cái trên ngoại trừ setTime()có một biến thể UTC, ví dụ : setUTCHours().

Như chúng ta có thể thấy, một số phương thức có thể thiết lập nhiều thành phần cùng một lúc, ví dụ setHours. Các thành phần không được đề cập sẽ không được sửa đổi.

Ví dụ:

let today = new Date();

today.setHours(0);
alert(today); // still today, but the hour is changed to 0

today.setHours(0, 0, 0, 0);
alert(today); // still today, now 00:00:00 sharp.

4. Tự động

Các autocorrection là một tính năng rất tiện dụng của các đối tượngDate. Chúng ta có thể đặt các giá trị ngoài phạm vi và nó sẽ tự động điều chỉnh.

Ví dụ:

let date = new Date(2013, 0, 32); // 32 Jan 2013 ?!?
alert(date); // ...is 1st Feb 2013!

Các thành phần ngày ngoài phạm vi của một thàng, ngày, năm, giờ, phút , giây sẽ được phân phối tự động.

Giả sử chúng ta cần tăng ngày 28 tháng 2 năm 2016 thêm 2 ngày. Đó có thể là một cuộc hẹn hò của 2 Mar hoặc 1 Mar trong trường hợp một năm nhuận. Chúng ta không cần phải suy nghĩ về nó. Chỉ cần thêm 2 ngày. Đối Datetượng sẽ làm phần còn lại:

let date = new Date(2016, 1, 28);
date.setDate(date.getDate() + 2);

alert( date ); // 1 Mar 2016

Tính năng đó thường được sử dụng để lấy ngày sau khoảng thời gian nhất định. Chẳng hạn, chúng ta hãy lấy ngày sau 70 giây tính từ ngay bây giờ

let date = new Date();
date.setSeconds(date.getSeconds() + 70);

alert( date ); // shows the correct date

Chúng ta cũng có thể đặt giá trị 0 hoặc thậm chí âm. Ví dụ:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

let date = new Date(2016, 0, 2); // 2 Jan 2016

date.setDate(1); // set day 1 of month
alert( date );

date.setDate(0); // min day is 1, so the last day of the previous month is assumed
alert( date ); // 31 Dec 2015

5. Chuyển ngày thành số

Khi một đối tượng Date được chuyển đổi thành số, nó sẽ trở thành dấu thời gian(timestamp) giống như date.getTime():

let date = new Date();
alert(+date); // the number of milliseconds, same as date.getTime()

Tác dụng phụ quan trọng: ngày có thể được trừ, kết quả là sự khác biệt của chúng trong mili giây.

Điều đó có thể được sử dụng để đo thời gian:

let start = new Date(); // start measuring time

// do the job
for (let i = 0; i < 100000; i++) {
  let doSomething = i * i * i;
}

let end = new Date(); // end measuring time

alert( `The loop took ${end - start} ms` );

6. Date.now()

Nếu chúng ta chỉ muốn đo thời gian, chúng ta không cần đối tượng Date.

Có một phương thức đặc biệt Date.now()trả về dấu thời gian(timestamp) hiện tại.

Nó tương đương về mặt ngữ nghĩa new Date().getTime(), nhưng nó không tạo ra một đối tượngDate trung gian. Vì vậy, nó nhanh hơn và không gây áp lực lên bộ dọn rác.

Nó được sử dụng chủ yếu để thuận tiện hoặc khi nâng cao hiệu suất hoạt động, như trong các trò chơi trong JavaScript hoặc các ứng dụng chuyên dụng khác.

Vì vậy, điều này có lẽ tốt hơn:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

let start = Date.now(); // milliseconds count from 1 Jan 1970

// do the job
for (let i = 0; i < 100000; i++) {
  let doSomething = i * i * i;
}

let end = Date.now(); // done

alert( `The loop took ${end - start} ms` ); // subtract numbers, not dates

7. Hiệu suất

Nếu CPU của bạn hạn chế, chúng ta nên cẩn thận.

Chẳng hạn, hãy đo hai hàm tính toán sự khác biệt giữa hai ngày: cái nào nhanh hơn?

Các phép đo hiệu suất như vậy thường được gọi là điểm chuẩn.

// we have date1 and date2, which function faster returns their difference in ms?
function diffSubtract(date1, date2) {
  return date2 - date1;
}

// or
function diffGetTime(date1, date2) {
  return date2.getTime() - date1.getTime();
}

Hai cái này thực hiện chính xác cùng một thứ, nhưng một trong số chúng sử dụng một từ rõ ràng date.getTime()để lấy ngày bằng ms(mili giây) và cái còn lại dựa vào biến đổi ngày thành số. Kết quả của họ luôn giống nhau.

Vậy, cái nào nhanh hơn?

Ý tưởng đầu tiên có thể là chạy chúng nhiều lần liên tiếp và đo chênh lệch thời gian. Đối với trường hợp của chúng ta, các hàm rất đơn giản, vì vậy chúng ta phải thực hiện ít nhất 100000 lần.

Hãy đo:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

function diffSubtract(date1, date2) {
  return date2 - date1;
}

function diffGetTime(date1, date2) {
  return date2.getTime() - date1.getTime();
}

function bench(f) {
  let date1 = new Date(0);
  let date2 = new Date();

  let start = Date.now();
  for (let i = 0; i < 100000; i++) f(date1, date2);
  return Date.now() - start;
}

alert( 'Time of diffSubtract: ' + bench(diffSubtract) + 'ms' );
alert( 'Time of diffGetTime: ' + bench(diffGetTime) + 'ms' );

Ồ Sử dụng getTime()nhanh hơn rất nhiều! Đó là bởi vì không có chuyển đổi kiểu, công cụ của Javascript sẽ dễ dàng tối ưu hóa hơn nhiều.

Được rồi, chúng ta có một cái gì đó. Nhưng đó chưa phải là một điểm chuẩn tốt.

Hãy tưởng tượng rằng tại thời điểm bench(diffSubtract)CPU đang chạy song song và nó đang lấy tài nguyên. Và đến lúc chạy xong bench(diffGetTime)thì công việc đã hoàn thành.

Một kịch bản khá thực tế cho một hệ điều hành đa tiến trình hiện đại.

Do đó, điểm chuẩn đầu tiên sẽ có ít tài nguyên CPU hơn so với lần thứ hai. Điều đó có thể dẫn đến kết quả sai.

Để điểm chuẩn đáng tin cậy hơn, toàn bộ gói điểm chuẩn phải được chạy lại nhiều lần.

Ví dụ, như thế này:

function diffSubtract(date1, date2) {
  return date2 - date1;
}

function diffGetTime(date1, date2) {
  return date2.getTime() - date1.getTime();
}

function bench(f) {
  let date1 = new Date(0);
  let date2 = new Date();

  let start = Date.now();
  for (let i = 0; i < 100000; i++) f(date1, date2);
  return Date.now() - start;
}

let time1 = 0;
let time2 = 0;

// run bench(upperSlice) and bench(upperLoop) each 10 times alternating
for (let i = 0; i < 10; i++) {
  time1 += bench(diffSubtract);
  time2 += bench(diffGetTime);
}

alert( 'Total time for diffSubtract: ' + time1 );
alert( 'Total time for diffGetTime: ' + time2 );

Các công cụ JavaScript hiện đại bắt đầu áp dụng tối ưu hóa nâng cao cho code thực thi nhiều lần (không cần tối ưu hóa khi được thực thi). Vì vậy, trong ví dụ trên, các lần thực hiện đầu tiên không được tối ưu hóa tốt. Chúng ta có thể muốn thêm một hoạt động tăng nhiệt:

// added for "heating up" prior to the main loop
bench(diffSubtract);
bench(diffGetTime);

// now benchmark
for (let i = 0; i < 10; i++) {
  time1 += bench(diffSubtract);
  time2 += bench(diffGetTime);
}

Hãy cẩn thận khi đánh dấu vĩ mô(microbenchmarking)

Các công cụ JavaScript hiện đại thực hiện nhiều tối ưu hóa. Họ có thể điều chỉnh kết quả của các bài kiểm tra nhân tạo, so với khi chúng ta sử dụng thông thường, đặc biệt là khi chúng ta điểm chuẩn(kiểm tra hiệu suất) một cái gì đó rất nhỏ, chẳng hạn như cách toán tử làm việc hoặc hàm tích hợp. Vì vậy, nếu bạn nghiêm túc muốn hiểu hiệu suất, thì hãy nghiên cứu cách hoạt động của công cụ JavaScript. Và sau đó bạn có thể sẽ không cần microbenchmark.

Các bài tuyệt vời về V8 có thể được tìm thấy tại http://mrale.ph.

8. Tạo ngày với format

Phương thức Date.parse(str) có thể đọc một ngày với format.

Định dạng chuỗi phải là : YYYY-MM-DDTHH:mm:ss.sssZ, trong đó:

  • YYYY-MM-DD – là ngày: năm-tháng-ngày.
  • Ký tự "T"được sử dụng như là dấu phân cách.
  • HH:mm:ss.sss – là thời gian: giờ, phút, giây và mili giây.
  • Phần tùy chọn 'Z'biểu thị múi giờ theo định dạng +-hh:mm. Một chữ cái Zcó nghĩa là UTC + 0.

Biến thể ngắn hơn có thể là YYYY-MM-DDhoặc YYYY-MMhoặc thậm chí YYYY.

Lệnh gọi Date.parse(str) để phân tích ngày theo định dạng đã cho và trả về dấu thời gian(timestamp) (số mili giây từ ngày 1 tháng 1 năm 1970 UTC + 0). Nếu định dạng không hợp lệ, trả về NaN.

Ví dụ:

let ms = Date.parse('2012-01-26T13:51:50.417-07:00');

alert(ms); // 1327611110417  (timestamp)

Chúng ta có thể ngay lập tức tạo một đối tượng new Date từ timestamp:

let date = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') );

alert(date);

9. Tóm lược

  • Ngày và thời gian trong JavaScript được biểu thị bằng đối tượng Date. Chúng ta không thể tạo ra “chỉ ngày” hoặc “chỉ có thời gian”: Dateđối tượng luôn mang theo cả hai.
  • Các tháng được tính từ 0 (có, tháng 1 là tháng không).
  • Số ngày trong tuần getDay()cũng được tính từ số không (đó là Chủ nhật).
  • Datetự động sửa khi các thành phần ngoài phạm vi được set vào. Cái này khá tốt khi thêm / trừ ngày / tháng / giờ.
  • Ngày có thể được trừ, cho ra kết quả tính bằng mili giây. Đó là bởi vì một Date được chuyển đổi thành timestamp rồi nó tiến hành trừ.
  • Sử dụng Date.now()để có được timestamp hiện tại một cách nhanh chóng.

Lưu ý rằng không giống như nhiều hệ thống khác, dấu thời gian(timestamp) trong JavaScript tính bằng mili giây chứ không phải tính bằng giây.

Đôi khi chúng ta cần đo thời gian chính xác hơn. Bản thân JavaScript không có cách đo thời gian tính bằng micro giây (1 phần triệu giây), nhưng hầu hết các môi trường đều cung cấp nó. Chẳng hạn, trình duyệt cóperformance.now() cung cấp số mili giây từ khi bắt đầu tải trang với độ chính xác micro giây (3 chữ số):

alert(`Loading started ${performance.now()}ms ago`);
// Something like: "Loading started 34731.26000000001ms ago"
// .26 is microseconds (260 microseconds)
// more than 3 digits after the decimal point are precision errors, but only the first 3 are correct

Node.js có microtimemô-đun và các cách khác. Về mặt kỹ thuật, hầu hết mọi thiết bị và môi trường đều cho phép có độ chính xác cao hơn, chỉ là không có Date.

Full series tự học Javascript từ cơ bản tới nâng cao tại đây nha.

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!