Trong bài trước, có một tình huống thế này:
Vậy nếu time-zone cần chuyển có dùng DST và không giống với time-zone của User thì phải làm sao?
Thật sự là mình không nghĩ ra được cách nào áp dụng cả 2 điều kiện trên bằng AMPscript được cả, chỉ còn cách tạo 1 staging DE giống hệt như vậy rồi dùng SQL xử lý và truyền vào lại lần nữa như bài trước ở option 1.
Thật ra thì vẫn có thể đưa thuần AMPscript vào để xử lý được, tuy nhiên nó phức tạp và cồng kềnh → người đọc dễ bị nhiễu thông tin nên Gâu Đần quyết định viết một bài riêng cho tình huống này.
Note:
- Bài này chỉ sử dụng thuần AMPscript.
- Tùy thuộc vào thời gian DST và khu vực bạn sẽ phải tự điều chỉnh lại cho phù hợp với cái mình muốn đạt được.
Tìm hiểu về cách tính DST ở khu vực đó
Đầu tiên, bạn muốn convert gì thì cần phải hiểu ở nơi có sử dụng Daylight Saving Time (DST) họ tính kiểu gì. Ở đây Đần lấy ví dụ là thời gian ở bang California(Mỹ)
Key information | Description |
Khu vực | California |
Ngày bắt đầu DST | Từ 2 giờ sáng ngày chủ nhật thứ hai trong tháng 3 |
Kết thúc DST | Đến 2 giờ sáng ngày chủ nhật đầu tiên trong tháng 11 |
DST thì sử dụng time-zone | UTC-7 |
Khi không DST thì sử dụng time-zone | UTC-8 |
Kiểm tra lại thử:
Giờ bạn mở lịch trong máy tính lên kiểm tra xem thử có đúng ngày chủ nhật thứ hai trong tháng 3, và ngày chủ nhật đầu tiên trong tháng 11 rơi vào những ngày như trên không (chú ý ở đây là năm 2022).
Okay hiểu về cách tính rồi phải không. Kết luận: chỉ cần so sánh ngày hiện tại cần convert vào trong khoảng thời điểm bắt đầu và kết thúc DST thì ta có thể biết được khu vực đó đang dùng offset gì (múi giờ gì), từ đó convert lại giờ.
Dùng AMPscript và convert time sang DST
Xác định thời gian mở đầu và kết thúc DST
Thời gian bắt đầu và kết thúc DST mỗi năm sẽ môi khác vì tùy thuộc vào hôm đó là ngày gì nữa. Vì thế trước tiên ta phải xác định thời gian bắt đầu và kết thúc.
Thuật toán ở đây là ta sẽ tìm hiểu ngày 1 của tháng 3 rơi vào thứ mấy. Từ đó tính ra ngày chủ nhật thứ 2 của tháng đó sẽ là ngày bao nhiêu. (và đừng quên cộng thêm 2 tiếng nữa nhé)
%%[
var @2nd_sunday_march, @1st_day_march, @1st_sunday_november, @1st_day_november, @local_time
/* get time and current year */
set @now = Now() /* Put your datetime needs to be converted HERE! */
set @year = FormatDate(@now, 'yyyy')
/* get 2nd sunday of march */
set @day = Concat('3/1/', @year)
set @1st_day_march = FormatDate(@day, 'dddd') /* date */
if @1st_day_march == 'Mon' then
set @day_number = Add(Add(1, 6), 7)
elseif @1st_day_march == 'Tue' then
set @day_number = Add(Add(1, 5), 7)
elseif @1st_day_march == 'Wed' then
set @day_number = Add(Add(1, 4), 7)
elseif @1st_day_march == 'Thur' then
set @day_number = Add(Add(1, 3), 7)
elseif @1st_day_march == 'Fri' then
set @day_number = Add(Add(1, 2), 7)
elseif @1st_day_march == 'Sat' then
set @day_number = Add(Add(1, 1), 7)
elseif @1st_day_march == 'Sun' then
set @day_number = Add(Add(1, 0), 7)
ENDIF
set @2nd_sunday_march = Concat(@day_number, '/', '03/', @year)
set @2nd_sunday_march = DateParse(@2nd_sunday_march, 0) /* convert string to date */
set @2nd_sunday_march = DateAdd(@2nd_sunday_march, '2', 'H')
]%%
Time before being converted: %%=v(@now)=%%<br>
2nd Sunday in March: %%=v(@2nd_sunday_march)=%%<br>
Tương tự ta sẽ tính được ngày chủ nhật đầu tiên của tháng 11 rơi vào ngày bao nhiêu (và đừng quên cộng thêm 2 tiếng nữa nhé)
%%[
var @2nd_sunday_march, @1st_day_march, @1st_sunday_november, @1st_day_november, @local_time
/* get time and current year */
set @now = Now() /* Put your datetime needs to be converted HERE! */
set @year = FormatDate(@now, 'yyyy')
/* get 1st sunday of november */
set @day = Concat('11/1/', @year)
set @1st_day_november = FormatDate(@day, 'dddd') /* date */
if @1st_day_november == 'Mon' then
set @day_number = Add(1, 6)
elseif @1st_day_november == 'Tue' then
set @day_number = Add(1, 5)
elseif @1st_day_november == 'Wed' then
set @day_number = Add(1, 4)
elseif @1st_day_november == 'Thur' then
set @day_number = Add(1, 3)
elseif @1st_day_november == 'Fri' then
set @day_number = Add(1, 2)
elseif @1st_day_november == 'Sat' then
set @day_number = Add(1, 1)
elseif @1st_day_november == 'Sun' then
set @day_number = Add(1, 0)
ENDIF
set @1st_sunday_november = Concat(@day_number, '/', '11/', @year)
set @1st_sunday_november = DateParse(@1st_sunday_november, 0) /* convert string to date */
set @1st_sunday_november = DateAdd(@1st_sunday_november, '2', 'H')
]%%
Time before being converted: %%=v(@now)=%%<br>
1st Sunday in November: %%=v(@1st_sunday_november)=%%<br>
Lưu ý: function DateParse
convert string thành date time và nó chỉ convert được khi format string và format date thuộc MC Business Unit là giống nhau.Chẳng hạn như BU của mình có time-zone là UTC-6 và Date Format là English (Singapore) nên format để dùng được function này phải là ngày trước tháng sau dd/mm/yyyy
Nếu BU của bạn có Date Format là English (United States) thì sao? Thì một là đổi lại y như mình, khỏi sửa code. Hai là sửa lại code sao cho 2 biến @2nd_sunday_march
và @1st_sunday_november
trước khi dùng DateParse
phải thuộc format tháng trước ngày sau mm/dd/yyyy
Nếu không thì sẽ hiện ra lỗi này nè:
String was not recognized as a valid DateTime
Tìm offset cho thời gian hiện tại
%%[
/* Find offset */
set @offset = IIf(@now >= @2nd_sunday_march AND @now <= @1st_sunday_november, -7, -8)
if @offset == -7 then
set @local_time = DateAdd(@now, -1, 'H')
set @local_time = FormatDate(@local_time, 'dd/mm/yyyy', 'HH:mm:ss') /*format if needed */
else
set @local_time = DateAdd(@now, -2, 'H')
set @local_time = FormatDate(@local_time, 'dd/mm/yyyy', 'HH:mm:ss') /*format if needed */
endif
]%%
Nếu đúng là thời gian nằm trong range đó thì tức lúc này đang dùng DST với time-zone là UTC-7 (sau 1 giờ so với system time UTC-6)
Còn nếu không phải tức là đang dùng thời gian chuẩn ở khu vực đó UTC-8 (sau 2 giờ so với system time UTC-6)
Final code:
%%[
var @2nd_sunday_march, @1st_day_march, @1st_sunday_november, @1st_day_november, @local_time
/* get time and current year */
set @now = Now() /* Put your datetime needs to be converted HERE! */
set @year = FormatDate(@now, 'yyyy')
/* get 2nd sunday of march */
set @day = Concat('3/1/', @year)
set @1st_day_march = FormatDate(@day, 'dddd') /* date */
if @1st_day_march == 'Mon' then
set @day_number = Add(Add(1, 6), 7)
elseif @1st_day_march == 'Tue' then
set @day_number = Add(Add(1, 5), 7)
elseif @1st_day_march == 'Wed' then
set @day_number = Add(Add(1, 4), 7)
elseif @1st_day_march == 'Thur' then
set @day_number = Add(Add(1, 3), 7)
elseif @1st_day_march == 'Fri' then
set @day_number = Add(Add(1, 2), 7)
elseif @1st_day_march == 'Sat' then
set @day_number = Add(Add(1, 1), 7)
elseif @1st_day_march == 'Sun' then
set @day_number = Add(Add(1, 0), 7)
ENDIF
set @2nd_sunday_march = Concat(@day_number, '/', '03/', @year)
set @2nd_sunday_march = DateParse(@2nd_sunday_march, 0) /* convert string to date */
set @2nd_sunday_march = DateAdd(@2nd_sunday_march, '2', 'H')
/* get 1st sunday of november */
set @day = Concat('11/1/', @year)
set @1st_day_november = FormatDate(@day, 'dddd') /* date */
if @1st_day_november == 'Mon' then
set @day_number = Add(1, 6)
elseif @1st_day_november == 'Tue' then
set @day_number = Add(1, 5)
elseif @1st_day_november == 'Wed' then
set @day_number = Add(1, 4)
elseif @1st_day_november == 'Thur' then
set @day_number = Add(1, 3)
elseif @1st_day_november == 'Fri' then
set @day_number = Add(1, 2)
elseif @1st_day_november == 'Sat' then
set @day_number = Add(1, 1)
elseif @1st_day_november == 'Sun' then
set @day_number = Add(1, 0)
ENDIF
set @1st_sunday_november = Concat(@day_number, '/', '11/', @year)
set @1st_sunday_november = DateParse(@1st_sunday_november, 0) /* convert string to date */
set @1st_sunday_november = DateAdd(@1st_sunday_november, '2', 'H')
/* find offset */
set @offset = IIf(@now >= @2nd_sunday_march AND @now <= @1st_sunday_november, -7, -8)
if @offset == -7 then
set @local_time = DateAdd(@now, -1, 'H')
set @local_time = FormatDate(@local_time, 'dd/mm/yyyy', 'HH:mm:ss') /*format if needed */
else
set @local_time = DateAdd(@now, -2, 'H')
set @local_time = FormatDate(@local_time, 'dd/mm/yyyy', 'HH:mm:ss') /*format if needed */
endif
]%%
Time before being converted: %%=v(@now)=%%<br>
2nd Sunday in March: %%=v(@2nd_sunday_march)=%%<br>
1st Sunday in November: %%=v(@1st_sunday_november)=%%<br>
Time after being converted: %%=v(@local_time)=%%<br>
Output:
Kiểm tra lại lần nữa
Conclusion
Vậy là đúng thời gian rồi nhé. Phù, vậy ta đã biết cách convert sang time-zone khác bằng AMPscript kể cả khi khu vực đó có dùng DST.
Bonus:
Bạn có để ý rằng các function AMPscript liên quan đến pull date time như SystemDateToLocalDate
, DateParse
- Trong content builder và preview and test mode thì time zone = Account time zone
- Time-zone và date-format khi ở trên Cloud page = User preferences time zone (chính xác là người tạo/người publish cái cloudpage này)
- Khi gửi email đến người nhận thì
SystemDateToLocalDate
, dù có hiển thị trên preview mode là theo BU settings nhưng end-user lại nhận theo time zone = User preferences time zone - Script Activity thì luôn là SystemDateToLocalDate = User preferences time zone
Rất thú vị và có gì đó khó hiểu phải không :))))