"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > 앱 및 백엔드 개발의 극단적 사례 — 날짜 및 시간

앱 및 백엔드 개발의 극단적 사례 — 날짜 및 시간

2024-08-14에 게시됨
검색:295

Introduction

You may think that dealing with dates and time is easy. We have a minute that lasts 60 seconds, an hour with 60 minutes, a day with 24 hours, a week with 7 days, a month with 28 to 31 days, and so on.

Surely no rocket science is required here…

Well, nothing could be further from the truth!

We will show the traps and pitfalls related to date and time that you may encounter during application and backend development.

Measurement units

Let’s start with the units of measurement, from the smallest ones to the largest.

Seconds and milliseconds

The smallest unit used everyday is a second. It is also the base of Unix time.

However, in some programming languages, such as Java, the most common unit is a millisecond (1/1000 of the second), as by the System.currentTimeMillis() method, for example.

That divergence may lead to many errors.

If you receive the numeric value from outside your system, it might not at first glance be clear what unit of measurement it uses, even after reading the documentation!

Look at the DATE field in the SMS and MMS content provider (database) columns. Both docs say only:

  • The date the message was received.

  • Type: INTEGER (long)

However, the SMS uses milliseconds while the MMS uses seconds. Surprised? Well, it may happen, especially if such APIs are designed by different people.

How can you deal with cases like these? And how can you avoid them?

Fortunately, we can formulate several general rules:

  1. Always ensure the format of incoming data.
    Check it in the wild because the documentation may be incorrect and/or outdated. It is usually very easy to spot an error, such as a date 50 thousand years too far in the future, when you look for it while developing. This result occurs when milliseconds are treated as seconds, for example.

  2. If you have any influence on the side which is sending the values (eg. the system is being designed and nobody uses it yet), consider the standardized textual formats.
    Here, I emphasize standardization (eg.ISO 8601) not some custom formats (we will broaden this topic later). After a few years, nobody from the original team may longer work for that project, and the textual format is straightforward to understand for new developers, as they don’t need to look at the docs.
    Numerical formats may be better, however, in performance-critical appliances.

  3. **Use dedicated classes for dealing with date/time/duration values rather than raw integers.
    **In the Java world, we have a java.time package with a lot of useful classes like Instant or Duration. If there is an integer called eg. eventDuration, it is not known whether it stores seconds or milliseconds - or maybe even days?

  4. If you must deal with raw values (integers, longs etc.) which you could not just wholly refactor, such as legacy code, include the unit of measurement with the variables/fields names.
    For example,eventDurationSeconds is unambiguous.

Leap seconds

You’ve probably heard about leap years. They differ from “normal” ones by being an extra day longer. We also have leap seconds!

Are they longer than non-leap seconds?

Well, it depends!

First, let’s start with a little bit of theory. The Earth is slowing down; really it is not a philosophical statement but a scientifically proven fact. It is called delta-T.

OK, so what does this mean in practice for us? Well, our units of measurement for time have a standardized length. The base unit is a second, which is defined as:

The time duration of 9 192 631 770 periods of the radiation corresponding to the transition between the two hyperfine levels of the fundamental unperturbed ground-state of the caesium-133 atom. (source: bipm.org)

That duration is constant, and informs all other units derived from seconds eg. a minute consists of 60 seconds, an hour is 60 minutes (3,600 seconds) and so on.

However, if the Earth slows down (and the day gets longer), we have to somehow accommodate that slowdown to ensure the time measured by our units is consistent with reality. This is done by inserting extra seconds — the leap seconds.

There are only 2 available slots for leap seconds in the year: the very end of June and December. The very end means the last day (30th or 31st respectively) just after 23:59:59 UTC (so local time varies).

After those normally last seconds, the additional leap second is inserted before moving to the next day. So, we can have 23:59:60 (61 seconds in a minute — as we count from‌ 0).

Edge Cases in App and Backend Development — Dates & Times

Due to the fact that the slowdown is not constant, the leap seconds are inserted irregularly. The latest one (at the time of writing this article in April 2021) occurred in December 2016, which was more than 4 years ago. However, the penultimate one was in June 2015, with only a 1.5-year difference between the two.

In some of the places where we can set the time — like physical wall clocks or some framework APIs, there may be no ability to observe and/or set the time with the leap second.

For example the old-fashioned Date Java class supports even double leap seconds — the range spreads from 0 to 61, so 62 seconds are possible!

However, the modern Instant class from the java.time package does not expose leap seconds to programmers. Leap second is stretched equally over the last 1,000 seconds of the day (those seconds are longer).

Note that, in theory, the leap second can be also negative. But it has not happened so far.

This means that a minute could consist of 59 seconds, which may lead to huge issues. For example, if some action is scheduled to occur at 23:59:59.001 and it turns out that desired time does not exist…

Fortunately analogously to spreading the visible seconds may also be shrunk being completely transparent to programmers.

We know that the 61tst second can exist, but what about the 62nd? Well, the documentation says:

It is extremely unlikely that two leap seconds will occur in the same minute, but this specification follows the date and time conventions for ISO C.

Indeed, in the C specification we have a [0, 61] range. But why? The same question bothered Paul Eggert, the author of tzdata (timezone database) in 1992. As we can read in the archive:

*“Because there really were two leap seconds in one year (on separate days), and someone on the ANSI C committee thought that they came on the same day.” *— source groups.google.com.

That slight interpretation error, which occurred several decades ago, is visible still now because the new implementation needs to be backwards compatible with these standards.

Let’s go to other edge cases in app and backend development.

The days

The minutes and hours do not involve any unexpected cases so let’s jump to the days.

What is a day? It depends! You can say that it lasts 24 hours from 00:00:00 to 23:59:60 (including the leap second ? ). Well, whether the latter is generally true, the day does not always last 24 hours, as it may be 23, 25 or even 21 and 27! Why those values? The answer is…

Daylight saving time

So-called DST or “summer time” advances the clocks in warmer months intended for reducing power consumption. Darkness begins later than in “regular” (non-DST) time. Nowadays, the necessity of DST is debatable because there are a lot of disadvantages. Some countries have even stopped observing DST recently (eg. Russia in 2014) due to them.

What are the problems with DST? Let’s see!

I won’t cover things like forgotten manual adjustments of wall clocks or delayed public transportation but, instead, I will focus on aspects related to backend and app development.

You may think that, in the summer time, we advance the clocks by 1 hour. This is not always the case! There are places in the world where the difference is 3 hours (like Casey) or 30 minutes (like Lord Howe Island).

Summer time, not exactly as the name suggests, can also cover some part of the spring or autumn but, generally, it is related to the warmer months. In turn, that depends on the hemisphere.

While in Europe there is a summer, in Australia there is a winter and vice versa. So, to put that in perspective, Australian summer time occurs during Europe’s winter!

What’s more, the definition of summer in terms of time depends on jurisdiction. In all the countries of the European Union, time is changed at the same moment so the time difference between Berlin and London, for example, is always 1 hour, no matter whether we are in summer or winter.

But let’s consider the time difference between Sydney and London. In this case, it depends on the day of the year! That’s because Sydney starts and stops observing DST at different dates than London.

Edge Cases in App and Backend Development — Dates & Times
Inspiration: timeanddate.com

For example, starting in January we have 10 hours difference. Sydney observes DST at that time but London does not. At the end of March, London starts observing DST, while the state in Sydney remains unchanged, so the difference reduces to 9 hours. Then in April, Sydney stops observing DST, so we have 8 hours. We have 3 different offsets. So the question about the time difference between Sydney and London has 3 answers!

Countries like the USA, EU members or Australia have, let’s say, stable jurisdictions with respect to DST. It is well known in advance when the transition occurs. However, it is not always the case, as some countries may change the laws unexpectedly. For example in 2020 in Fiji, the rules have changed with the announcement only arriving a few months before.

Even more complicated situations occur in some Islamic countries that officially observe Ramadan. If they also observe DST, the latter may be… suspended (for the period of Ramadan).

That means the DST transition may occur more than once (back and forth) and even a few times in a year. Furthermore, Ramadan is calculated according to the Islamic (lunar) calendar. Prediction is used to calculate Ramadan boundary dates and it may not be always accurate. For example, in Palestine in 2020, the prediction turns out to be short by about a week. Changes were applied only a few days in advance.

Most of the systems use the IANA Time Zone database as the source of DST transition moments. There are usually a few updates each year in that database.

Note that dealing with DST may have an impact on algorithms. Let’s consider a few typical scenarios.

If we have an alarm scheduled to a particular wall time (eg. 02:30) it may turn out that such a moment does not exist (when time is changed from 02:00 to 03:00 during DST transition) or it exists twice when the time is changed backwards. If, for example, the backup won’t be done or medicates won’t be given or will be given twice, then the consequences may be terrible.

Another common effect consists of cyclical triggering time changes if the user is located in the timezone observing DST. For example, if you schedule a build on bitrise.io to be fired at 10:00, it may suddenly start firing at 11:00.

This happens because the logic under the hood is not aware of DST and the time visible to the user is only calculated when rendering the UI. The absolute moment in time is always the same but the time visible to the user changes depending on DST. Usually, it is not what customers expect.

The weeks

What is the first day of the week? If you live in Europe, you would probably say Monday. In the USA it will be Sunday and in Arabic countries — Saturday. These facts may impact algorithm constructing and/or rendering calendars.

What about the week number in the year? You may think that everything starts from January 1st.

As you might have guessed, this is also not always the case!

According to the ISO standard, the 1st week of the year must contain Thursday. For example, in 2021 January 1st is on Friday so it belongs to the last week of the previous year. The first week of 2021 started on January 4th! Not all the locales use the same rule as the ISO standard in that matter, however.

The months

The Gregorian calendar used by most of the world has 12 months, from January to December. However, other kinds of calendar may have more months. For example the Hebrew calendar may have 13 months. The 13th one (in the IT world) is called Undecimber.

The years

Usually, the year lasts 365 days. However, each one divisible by 4 (eg. 2020, 2024 etc.) is a leap year which has 366 days (with 29 days in February instead of the normal 28). But, if it is divisible by 100 (2100, 2200 etc.) it is NOT a leap year. But ? if it is divisible by 400 (2000, 2400 etc.) it is a leap year.

Fortunately, you don’t have to (and should not!) try to implement such distinctions yourself. You should use date classes/functions well known libraries of the given programming language.

There were many spectacular bugs in well-known services related to incorrect leap year calculations. There is even a term: Leap year problem.

The timezones

The local time depends on the longitude. While it’s noon in a particular location, it’s also midnight on the other side of the globe.

It is impractical to adjust the clocks continuously when traveling, so the globe was divided into zones which cover the areas having the same local official time.

Zone boundaries are usually equal to country boundaries in the case of small countries or some geographical regions in the biggest ones (like Australia, USA or Russia).

Edge Cases in App and Backend Development — Dates & Times
Source: timeanddate.com

Due to political and economical reasons in some places, the official time varies significantly from the “legitimate” one (taking only longitude/sun time into account). For example, in Spain, the zone is the same as in most of continental central Europe rather than the United Kingdom, which is closer according to the longitude.

Most time zones have integral offsets (the difference from UTC — a standard time) eg. in Berlin 1 hour ( 2 in DST) or -3 h in Buenos Aires (Argentina, no DST). However, the offset may include halves of hours eg. in Mumbai (India) we have 5:30h (no DST).

If that wasn’t enough, quarters are also possible, as in Kathmandu (Nepal) we have 5:45h!

Fortunately, there are no more finer-grained offsets at the time of writing. However, they used to exist in the past, such as 0:20 in the Netherlands.

Due to the fact that we have 24 hours on the clocks, one may think that it is also a range of possible offsets. 12:00 and -12:00 combined together gives 24.

However, the farthest time distance between time zones is 26 hours!

This is possible because we have a 14:00 offset. It was adopted by several countries in Oceania as they are rather connected with Australia, so it is more practical to have a few hours difference than more than 20, which leads to another date in most cases.

Let’s consider a flight connection finder. In the case of round-trip flights, the users can choose both departure and return dates/times. It may be obvious that the return time must be after the departure.

Of course, this couldn’t be further from the truth!

Keep in mind that those times are in local time zones.

Take a look at this example:

  1. Departure from Tokyo at 00:30 (offset 09:00) to San Francisco (offset -07:00)

  2. Arrival in San Francisco at 18:00, the previous day in local time!

  3. Return from San Francisco at 19:50 (still previous when relative to initial departure)

So, you can go somewhere and return yesterday. See this example:

Edge Cases in App and Backend Development — Dates & Times

Time zone naming

Another potential edge case in app/backend development you may face is connected to time zone naming.

You might notice that we can call a timezone by its offset eg. 01:00 or by its identifier eg. Europe/Berlin. Note that the latter notation gives multiple benefits: it carries information about DST transitions (Berlin has an offset 02:00 in the summer) and it also holds historical data.

For example, both the Europe/Warsaw and Europe/Berlin zones seem to be identical nowadays. They both have equal offsets all year, with DST transitions also always occurring at the same moments.

However, it was not always the case in the past! For example, in 1977 there was no DST in Berlin at all but Warsaw observed it from April 3th to September 25th (completely different from what we have today).

Note that timezone identifiers are built upon city names. This is intentional due to the fact that country boundaries are subject to change much more often than city names.

For example, the Crimea has in fact changed from Ukraine to Russia but the city names stay unchanged. The Europe/Simferopol zone can be used no matter if we need current or historical data.

Day vs nychthemeron, period vs duration

Let’s say that something lasts one day. So, if it starts at 09:15:00 AM then we can add 24 hours and to get the ending time (09:15:00 AM next day exclusively, in this case).

Well, it is not always so easy! Keep in mind that we can have a DST transition when the clock is artificially adjusted forward or backwards. This means the day usually lasts 24 hours but, occasionally, it may be 23, 25 or even more strange values like 27 or 23 and a half hours (do you remember Casey and Lord Howe?).

It is important to not blindly treat days as 24 hours when implementing business logic. You should use the appropriate date/time APIs for that. For example, in Java, we have distinct classes:

  • Period, which represents calendar days — perfect for things like subscription validity which is measured in days, months or years

  • Duration, which represents continuous time eg. 24 hours, no matter what the date in the calendar is. It’s perfect for measuring spans of actions, such as travel or the time since device/program start.

Some languages have distinct words for sunlit states (in English — day) and consecutive 24 hours (in English — nychthemeron, but it’s not commonly used).

Date/time representation:

Edge Cases in App and Backend Development — Dates & Times
Source: xkcd.com

When communicating with other systems, such as via REST API, it is important to agree about data formats. If you see a date displayed as 10/12/2021, it may be in either the US format (October 12th) or UK format (December 10th).

It is better to use some unambiguous representation!

For date and time, we have the ISO 8601 standard. Note that not only absolute date/times are standardized, but also periods. It is also important to use the proper type — local (for representing data like alarm clock triggering times or dates of birth) or zoned (for representing moments in time, like event starts or taking pictures).

Custom, non-standardized formats usually lead to confusion and bugs, so avoid them.

When displaying the date and time in the UI, you have to take the user’s locale into account. The displayed format depends on the language and region. Look at the following examples which all refer to the same date:

  • 4/18/21 — US English

  • 18/04/2021 — UK English

  • 18.04.2021 — Romanian

  • ١٨‏/٤‏/٢٠٢١ — Saudi Arabia, Arabic with Eastern Arabic numerals

There are predefined format types provided by date/time libraries, such as FormatStyle in java.time. Use them if possible. Otherwise, you can construct more customized formats using standardized pattern symbols. See the CLDR documentation for more details.

It is worth noting that, in the case of months, quarters, and days of weeks, there are also standalone variants. They are meaningful only in some languages (not in English). In Polish, for example, April is called kwiecień — this is a standalone version. However, if it connected with a day (eg. April 18th) the text becomes 18 kwietnia.

Wrap up

Dealing with dates and time is not straightforward. However, if you follow the standards described above and use proper types, you can avoid huge mistakes.

I hope my insight on dates and time edge cases will be useful in your projects. Good luck!

Originally published at https://www.thedroidsonroids.com on April 26, 2021.

릴리스 선언문 본 글은 https://dev.to/koral/edge-cases-in-app-and-backend-development-dates-times-16o5?1 에서 복제하였습니다. 침해 내용이 있는 경우, [email protected]으로 연락주시기 바랍니다. 그것을 삭제하려면
최신 튜토리얼 더>
  • 제로에서 웹 개발자로 전환: PHP의 기초 익히기
    제로에서 웹 개발자로 전환: PHP의 기초 익히기
    PHP의 기본을 마스터하는 것은 필수입니다. PHP 설치 PHP 파일 만들기 코드 실행 변수 및 데이터 유형 이해 표현식 및 연산자 사용 기술 향상을 위한 실제 프로젝트 만들기 PHP 개발 시작하기: PHP 기본 익히기PHP는 동적 및 대화형 웹 애플리케이션을 만들...
    프로그램 작성 2024-11-05에 게시됨
  • 버퍼: Node.js
    버퍼: Node.js
    Node.js의 버퍼에 대한 간단한 가이드 Node.js의 버퍼는 원시 바이너리 데이터를 처리하는 데 사용되며, 이는 스트림, 파일 또는 네트워크 데이터로 작업할 때 유용합니다. 버퍼를 만드는 방법 문자열에서: const buf = ...
    프로그램 작성 2024-11-05에 게시됨
  • Node.js의 버전 관리 마스터하기
    Node.js의 버전 관리 마스터하기
    개발자로서 우리는 다양한 Node.js 버전을 요구하는 프로젝트를 자주 접하게 됩니다. 이 시나리오는 Node.js 프로젝트에 정기적으로 참여하지 않는 신규 개발자와 숙련된 개발자 모두에게 함정입니다. 즉, 각 프로젝트에 올바른 Node.js 버전이 사용되는지 확인하는...
    프로그램 작성 2024-11-05에 게시됨
  • 문제 해결을 위해 Go 바이너리에 Git 개정 정보를 포함하는 방법은 무엇입니까?
    문제 해결을 위해 Go 바이너리에 Git 개정 정보를 포함하는 방법은 무엇입니까?
    Go 바이너리에서 Git 개정 확인코드를 배포할 때 바이너리를 빌드된 Git 개정과 연결하는 것이 도움이 될 수 있습니다. 문제 해결 목적. 그러나 개정 번호로 소스 코드를 직접 업데이트하는 것은 소스를 변경하므로 불가능합니다.해결책: 빌드 플래그 활용이 문제에 대한 ...
    프로그램 작성 2024-11-05에 게시됨
  • 일반적인 HTML 태그: 관점
    일반적인 HTML 태그: 관점
    HTML(HyperText Markup Language)은 웹 개발의 기초를 형성하며 인터넷의 모든 웹페이지 구조 역할을 합니다. 2024년 가장 일반적인 HTML 태그와 고급 용도를 이해함으로써 개발자는 보다 효율적이고 접근 가능하며 시각적으로 매력적인 웹 페이지를 ...
    프로그램 작성 2024-11-05에 게시됨
  • CSS 미디어 쿼리
    CSS 미디어 쿼리
    웹사이트가 다양한 기기에서 원활하게 작동하도록 보장하는 것이 그 어느 때보다 중요합니다. 사용자가 데스크톱, 노트북, 태블릿, 스마트폰에서 웹사이트에 액세스함에 따라 반응형 디자인이 필수가 되었습니다. 반응형 디자인의 중심에는 개발자가 사용자 기기의 특성에 따라 다양한...
    프로그램 작성 2024-11-05에 게시됨
  • JavaScript의 호이스팅 이해: 종합 가이드
    JavaScript의 호이스팅 이해: 종합 가이드
    자바스크립트에서 호이스팅 호이스팅은 변수 및 함수 선언을 포함 범위(전역 범위 또는 함수 범위)의 맨 위로 이동(또는 "호이스팅")하는 동작입니다. 코드가 실행됩니다. 즉, 코드에서 실제로 선언되기 전에 변수와 함수를 사용할 수 있습니...
    프로그램 작성 2024-11-05에 게시됨
  • Stripe를 단일 제품 Django Python Shop에 통합
    Stripe를 단일 제품 Django Python Shop에 통합
    In the first part of this series, we created a Django online shop with htmx. In this second part, we'll handle orders using Stripe. What We'll...
    프로그램 작성 2024-11-05에 게시됨
  • Laravel에서 대기 중인 작업을 테스트하기 위한 팁
    Laravel에서 대기 중인 작업을 테스트하기 위한 팁
    Laravel 애플리케이션으로 작업할 때 명령이 비용이 많이 드는 작업을 수행해야 하는 시나리오를 접하는 것이 일반적입니다. 기본 프로세스를 차단하지 않으려면 대기열에서 처리할 수 있는 작업으로 작업을 오프로드하기로 결정할 수 있습니다. 예제를 살펴보겠습니다. app:...
    프로그램 작성 2024-11-05에 게시됨
  • 인간 수준의 자연어 이해(NLU) 시스템을 만드는 방법
    인간 수준의 자연어 이해(NLU) 시스템을 만드는 방법
    Scope: Creating an NLU system that fully understands and processes human languages in a wide range of contexts, from conversations to literature. ...
    프로그램 작성 2024-11-05에 게시됨
  • JSTL을 사용하여 HashMap 내에서 ArrayList를 반복하는 방법은 무엇입니까?
    JSTL을 사용하여 HashMap 내에서 ArrayList를 반복하는 방법은 무엇입니까?
    JSTL을 사용하여 HashMap 내에서 ArrayList 반복웹 개발에서 JSTL(JavaServer Pages Standard Tag Library)은 JSP( 자바 서버 페이지). 그러한 작업 중 하나는 데이터 구조를 반복하는 것입니다.HashMap과 그 안에 포...
    프로그램 작성 2024-11-05에 게시됨
  • Encore.ts — ElysiaJS 및 Hono보다 빠릅니다.
    Encore.ts — ElysiaJS 및 Hono보다 빠릅니다.
    몇 달 전 우리는 TypeScript용 오픈 소스 백엔드 프레임워크인 Encore.ts를 출시했습니다. 이미 많은 프레임워크가 있으므로 우리는 우리가 내린 흔하지 않은 디자인 결정과 그것이 어떻게 놀라운 성능 수치로 이어지는지 공유하고 싶었습니다. 성능 ...
    프로그램 작성 2024-11-05에 게시됨
  • 문자열 리터럴에서 +를 사용한 문자열 연결이 실패하는 이유는 무엇입니까?
    문자열 리터럴에서 +를 사용한 문자열 연결이 실패하는 이유는 무엇입니까?
    문자열 리터럴을 문자열과 연결C에서는 연산자를 사용하여 문자열과 문자열 리터럴을 연결할 수 있습니다. 그러나 이 기능에는 혼란을 초래할 수 있는 제한 사항이 있습니다.질문에서 작성자는 문자열 리터럴 "Hello", ",world" 및...
    프로그램 작성 2024-11-05에 게시됨
  • React Re-Rendering: 최적의 성능을 위한 모범 사례
    React Re-Rendering: 최적의 성능을 위한 모범 사례
    React의 효율적인 렌더링 메커니즘은 React가 인기를 얻는 주요 이유 중 하나입니다. 그러나 애플리케이션이 복잡해짐에 따라 구성 요소 다시 렌더링을 관리하는 것이 성능을 최적화하는 데 중요해졌습니다. React의 렌더링 동작을 최적화하고 불필요한 재렌더링을 방지하...
    프로그램 작성 2024-11-05에 게시됨
  • 조건부 열 생성을 달성하는 방법: Pandas DataFrame에서 If-Elif-Else 탐색?
    조건부 열 생성을 달성하는 방법: Pandas DataFrame에서 If-Elif-Else 탐색?
    조건부 열 생성: Pandas의 If-Elif-Else주어진 문제에서는 DataFrame에 새 열을 추가해야 합니다. 일련의 조건부 기준을 기반으로 합니다. 문제는 코드 효율성과 가독성을 유지하면서 이러한 조건을 구현하는 것입니다.함수 적용을 사용한 솔루션한 가지 접근...
    프로그램 작성 2024-11-05에 게시됨

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3