Изображение © Марк Бойл | Съвет за деня на Австралия на Нов Южен Уелс.
Изображенията са собственост на съответния(ите) изпълнител(и). Всички права запазени.
AT TIME ZONE е толкова страхотна функция и не я бях забелязал доскоро, въпреки че Microsoft има страница за нея от декември.
Живея в Аделаида в Австралия. И като над милиард други хора по света, хората от Аделаида трябва да се справят с това, че са в половинчасова часова зона. През зимното време сме UTC+9:30, а през лятото сме UTC+10:30. С изключение на това, че ако четете това в северното полукълбо, ще трябва да запомните, че под „зима“, имам предвид април до октомври. Лятното часово време е от октомври до април, а Дядо Коледа седи на плажа със студена напитка, изпотявайки се през дебелия си червен костюм и брада. Освен ако не спасява животи, разбира се.
В Австралия имаме три основни часови зони (западна, централна и източна), но това се простира до пет през лятото, тъй като трите щата, които се простират до северния край на Австралия (WA, Qld и NT), не опитайте се да запазите всякаква дневна светлина. Те са достатъчно близо до екватора, за да не ги интересува или нещо подобно. Това е много забавно за летище Голд Коуст, чиято писта пресича границата NSW-QLD.
Сървърите за бази данни често работят в UTC, защото е просто по-лесно да не се занимавате с преобразуване между UTC и локално (и обратно) в SQL Server. Преди много години си спомням, че трябваше да коригирам доклад, който изброява инциденти, възникнали заедно с времето за реакция (оттогава пиша за това в блог). Измерването на SLA беше доста просто – видях, че един инцидент се случи по време на работното време на клиента и че те отговориха в рамките на един час. Виждах, че друг инцидент се е случил извън работно време и отговорът е в рамките на два часа. Проблемът се появи, когато беше изготвен отчет в края на период, когато часовата зона се промени, което доведе до инцидент, който действително се е случил в 17:30 (външно време), да бъде посочен като че ли се е случил в 16:30 (вътрешно време) . Отговорът отне около 90 минути, което беше наред, но отчетът показваше друго.
Всичко това е поправено в SQL Server 2016.
Как да използвате AT TIME ZONE в SQL Server 2016
Сега, с AT TIME ZONE, вместо да казвам:'20160101 00:00 +10:30', мога да започна със стойност за дата и час, която няма изместване на часовата зона, и да използвам AT TIME ZONE, за да обясня, че е в Аделаида.
ИЗБЕРЕТЕ CONVERT(datetime,'20160101 00:00') В ЧАСОВА ЗОНА „Цен. Австралийско стандартно време“; -- 2016-01-01 00:00:00.000 +10:30
И това може да се преобразува в американско време, като се добави отново AT TIME ZONE.
ИЗБЕРЕТЕ CONVERT(datetime,'20160101 00:00') В ЧАСОВА ЗОНА „Цен. Австралийско стандартно време“ В ЧАСОВА ЗОНА „Източно стандартно време на САЩ“; -- 31.12.2015 08:30:00.000 -05:00
Сега знам, че това е много по-дълготрайно. И трябва изрично да конвертирам низа в datetime, за да избегна грешка, казваща:
Аргументният тип данни varchar е невалиден за аргумент 1 на функцията AT TIME ZONE.Но въпреки дълготрайността му, аз го харесвам, защото в нито един момент не ми се наложи да разбера, че Аделаида е в +10:30, или че Източната е -5:00 – просто трябваше да знам часовата зона по име. Разбрах дали лятното часово време трябва да се прилага или не, беше обработено за мен и не ми се наложи да правя никакво преобразуване от локално към UTC, за да установя някаква базова линия.
Работи с помощта на системния регистър на Windows, който съдържа цялата тази информация, но за съжаление не е перфектен, когато гледате назад във времето. Австралия промени датите през 2008 г., а САЩ промениха датите си през 2005 г. – и двете страни запазват дневната светлина за по-голяма част от годината. AT TIME ZONE разбира това. Но изглежда не оценява, че в Австралия през 2000 г., благодарение на Олимпийските игри в Сидни, Австралия започна лятното часово време около два месеца по-рано. Това е малко разочароващо, но не е грешка на SQL – трябва да обвиняваме Windows за това. Предполагам, че системният регистър на Windows не помни актуалната корекция, която се появи през тази година. (Забележка за себе си:може да се наложи да помоля някой от екипа на Windows да поправи това...)
Полезността обаче продължава!
Това име на часовата зона дори не трябва да е константа. Мога да предавам променливи и дори да използвам колони:
С PeopleAndTZs AS( SELECT * FROM (СТОЙНОСТИ ('Rob', 'Cen. Australia Standard Time'), ('Paul', 'New Zealand Standard Time'), ('Aaron', 'US Eastern Standard Time' ) ) t (лице, tz))ИЗБЕРЕТЕ tz.person, SYSDATETIMEOFFSET() В ЧАСОВА ЗОНА tz.tz ОТ PeopleAndTZs tz; /* Роб 2016-07-18 18:29:11.9749952 +09:30 Пол 2016-07-18 20:59:11.9749952 +12:00 Аарон 2016-07-18 04:59:99:102. /предварително>(Защото го пуснах малко преди 18:30 ч. тук в Аделаида, което е почти 21 ч. в Нова Зеландия, където е Пол, и почти 5 ч. сутринта тази сутрин в източната част на Америка, където е Аарон.)
Това ще ми позволи лесно да видя колко е часът за хората, където и да се намират по света, и да видя кой би бил най-добре да отговори на някакъв проблем, без да се налага да извършвам ръчни преобразувания на дата и час. И още повече, това ще ми позволи да го направя за хора в миналото. Мога да имам отчет, който анализира кои часови зони биха позволили най-голям брой събития да се случат през работното време.
Тези часови зони са изброени в
sys.time_zone_info
, заедно с това какво е текущото изместване и дали в момента се прилага лятно часово време.
име | current_utc_offset | is_currently_dst |
---|---|---|
Стандартно време в Сингапур | +08:00 | 0 |
У. Австралийско стандартно време | +08:00 | 0 |
Стандартно време в Тайпе | +08:00 | 0 |
Стандартно време в Улан Батор | +09:00 | 1 |
Стандартно време на Северна Корея | +08:30 | 0 |
Aus Central W. Стандартно време | +08:45 | 0 |
Забайкалско стандартно време | +09:00 | 0 |
Стандартно време в Токио | +09:00 | 0 |
Извадка от редове от sys.time_zone_info
Наистина ме интересува само как се казва, но все пак. И е интересно да се види, че има часова зона, наречена „Aus Central W. Standard Time“, която е на четвърт час. Давай фигура. Също така си струва да се отбележи, че местата се споменават с помощта на тяхното стандартно време, дори ако в момента наблюдават DST. Като например Улан Батор в този списък по-горе, който не е посочен като лятно време на Улан Батор. Това може да изкара хората за цикъл, когато започнат да използват AT TIME ZONE.
Може ли AT TIME ZONE да причини проблеми с производителността?
Сигурен съм, че се чудите какво може да повлияе използването на AT TIME ZONE върху индексирането.
По отношение на формата на плана, не е по-различно да се занимавате с изместване на датата и времето като цяло. Ако имам стойности за дата и време, като например в колоната на AdventureWorks Sales.SalesOrderHeader.OrderDate (при която създадох индекс, наречен rf_IXOD), тогава изпълнявам и двете тази заявка:
изберете OrderDate, SalesOrderID от Sales.SalesOrderHeader, където OrderDate>=convert(datetime,'20110601 00:00') в часовата зона „US Eastern Standard Time“ и OrderDateИ тази заявка:
изберете OrderDate, SalesOrderID от Sales.SalesOrderHeader, където OrderDate>=convert(datetimeoffset,'20110601 00:00 -04:00') и OrderDateИ в двата случая получавате планове, които изглеждат така:
Но ако разгледаме малко по-внимателно, има проблем.
Този, който използва AT TIME ZONE, не използва много добре статистиката. Той мисли, че ще види 5 170 реда да излязат от това търсене на индекс, докато всъщност има само 217. Защо 5 170? Е, скорошната публикация на Аарон, „Обръщане на внимание на оценките“, го обяснява, като се позовава на публикацията „Оценка на кардиналността за множество предикати“ от Пол. 5170 е 31 465 (редове в таблицата) * 0,3 * sqrt(0,3).
Втората заявка го получава правилно, оценявайки 217. Виждате, че няма включени функции.
Това вероятно е достатъчно справедливо. Искам да кажа – в момента, когато създава плана, той няма да е поискал от регистъра информацията, от която се нуждае, така че наистина не знае колко да изчисли. Но има потенциал това да е проблем.
Ако добавя допълнителни предикати, за които знам, че не могат да бъдат проблем, тогава оценките ми всъщност намаляват още повече – до 89,9 реда.
изберете OrderDate, SalesOrderID от Sales.SalesOrderHeader, където OrderDate>=convert(datetime,'20110601 00:00') в часовата зона „US Eastern Standard Time“ и OrderDate=convert(datetimeoffset,'20110601 00:00 +14:00') и OrderDate Изчисляването на твърде много редове означава, че се разпределя твърде много памет, но оценяването на твърде малко може да причини твърде малко памет, с потенциална нужда от разливане за коригиране на проблема (което често може да бъде катастрофално от гледна точка на производителността). Прочетете публикацията на Аарон за повече информация относно това колко лоши оценки могат да бъдат лоши.
Когато обмисля как да се справя с показването на стойности за тези хора от преди, мога да използвам заявки като това:
С PeopleAndTZs AS( SELECT * FROM (СТОЙНОСТИ ('Rob', 'Cen. Australia Standard Time'), ('Paul', 'New Zealand Standard Time'), ('Aaron', 'US Eastern Standard Time' ) ) t (лице, tz))ИЗБЕРЕТЕ tz.person, o.SalesOrderID, o.OrderDate AT TIME ZONE 'UTC' AT TIME ZONE tz.tzFROM PeopleAndTZs tzCROSS JOIN Sales.SalesOrderHeader o.SalesOrderHeader o.SalesWEENOrderID404040; предварително>И вземете този план:
...което няма такива опасения – най-десният изчислителен скалар преобразува датата и часът OrderDate в datetimeoffset за UTC, а най-левият изчислителен скалар го преобразува в подходящата часова зона за лицето. Предупреждението е, защото правя КРЪСТО ПРИСЪЕДИНЯВАНЕ и това беше напълно умишлено.
Предимства и недостатъци на други методи за преобразуване на времето
Преди AT TIME ZONE, една от любимите ми, но често неоценени функции на SQL 2008 беше типът данни datetimeoffset. Това позволява данни за дата/час да се съхраняват и с часовата зона, като например „20160101 00:00 +10:30“, когато празнувахме Нова година в Аделаида тази година. За да видя кога това е било в Източната част на САЩ, мога да използвам функцията SWITCHOFFSET.
ИЗБЕРЕТЕ SWITCHOFFSET('20160101 00:00 +10:30', '-05:00'); -- 2015-12-31 08:30:00.0000000 -05:00Това е същият момент във времето, но в различна част на света. Ако говоря по телефона с някого в Северна Каролина или Ню Йорк и му пожелавам Честита Нова година, защото беше точно минало полунощ в Аделаида, те щяха да ми кажат „Какво искаш да кажеш? Все още е време за закуска тук в навечерието на Нова година!”
Проблемът е, че за да направя това, трябва да знам, че през януари Аделаида е +10:30, а Източната част на САЩ е –5:00. И това често е болка. Особено ако питам за края на март, началото на април, октомври, началото на ноември – онези времена от годината, когато хората не могат да бъдат сигурни в коя часова зона са били хората в други страни, защото се променят с един час за лятно часово време и те всички го правят според различни правила. Компютърът ми ми казва в коя часова зона се намират хората сега, но е много по-трудно да кажа в коя часова зона ще бъдат през друго време на годината.
За друга информация относно преобразуването между часови зони и как хора като Аарон са се справили с лятното часово време, вижте следните връзки:
- Използване на AT TIME ZONE за коригиране на стар отчет (това съм аз!)
- Управлявайте преобразуването между часовите зони в SQL Server – част 1
- Управлявайте преобразуването между часовите зони в SQL Server – част 2
- Управлявайте преобразуването между часовите зони в SQL Server – част 3
И малко официална документация на Microsoft:
- В ЧАСОВА ЗОНА (Transact-SQL)
- sys.time_zone_info (Transact-SQL)
- Помощ и поддръжка за лятно часово време
Трябва ли да използвате AT TIME ZONE?
AT TIME ZONE не е идеален. Но е наистина полезно – невероятно. Той е достатъчно гъвкав, за да приема колони и променливи като вход и виждам огромен потенциал за него. Но ако това ще доведе до изваждане на моите оценки, тогава ще трябва да бъда внимателен. За целите на показване това изобщо не би трябвало да има значение и точно там виждам, че е най-полезно. Улесняването на преобразуването на показвана стойност към или от UTC (или към или от местно време), без някой да се налага да си прави мозъци за компенсации и DST, е голяма печалба.
Това наистина е една от любимите ми функции на SQL Server 2016. Плачех за нещо подобно от много дълго време.
О, и повечето от тези милиарди хора в половинчасовата часова зона са в Индия. Но вероятно вече сте знаели, че...