Developing applications for the mobile platform Android requires a deep understanding of working with timestamps, since this functionality is in demand in almost every product. Whether it's a simple display of a user's date of birth, event logging, or complex task scheduling algorithms, the ability to correctly extract the current time is a basic programmer skill. However, approaches to solving this problem changed dramatically with the release of new versions of the operating system and updating of programming language standards.
Historically, early versions Android SDK relied on outdated classes from packages java.utilwhich had many architectural shortcomings, including problems with thread safety and complex logic for working with time zones. Modern developers are increasingly switching to java.time API, which was introduced into the Java 8 standard library and became available on Android starting with API 26, and for older versions - through the library ThreeTenABP. Understanding the evolution of these tools is critical to writing maintainable code.
In this article, we'll take a closer look at the different ways to get the current date, compare code performance and readability, and look at common mistakes newbies make when working with time intervals. Particular attention will be paid to the differences between implementations in languages Java and Kotlin, since the syntactic features of the latter allow you to write more concise and secure solutions. You'll learn how to avoid common pitfalls when formatting output and why avoiding legacy methods is not only a matter of aesthetics, but also the stability of your application.
The traditional approach using the Date class
In the early days of the platform, the only way to get the current time was to use the java.util.Dateclass. This object represents a specific moment in time with millisecond precision, measured from the so-called "Unix epoch" (January 1, 1970). Although this class is marked as obsolete in many modern contexts, it is still widely found in legacy code and some system libraries. Android.
To create an instance containing the current moment, simply call the constructor without arguments. This action instantly captures the device's system time at the moment the line of code is executed. However, it is important to understand that the object itself Date does not store information about the time zone or locale, it represents only the absolute value of time in milliseconds.
import java.util.Date;Date currentDate = new Date;
long milliseconds = currentDate.getTime;
The main problem with this approach is the mutable nature of objects: the class Date is mutable, which creates risks during multi-threaded data processing. If you pass this object to another thread and change its state, it can introduce hard-to-catch errors in your application logic. In addition, the methods for working with individual date components (year, month, day) in this class have long been considered obsolete and are not recommended for use in new development.
โ ๏ธ Attention: The class
Dateis not intended for formatting or retrieving individual fields (day, month) directly. Trying to use methods likegetYearorgetMonthwill lead to compiler warnings and potential bugs due to the specific numbering of months (starting from 0).
Modern standard java.time API
Starting with version Android 8.0 (API level 26), the platform received full support for the library java.time, which replaced outdated classes. This API, also known as JSR-310, was developed taking into account all the shortcomings of previous solutions and offers immutable (immutable), thread-safe and intuitive classes for working with time.
The class LocalDateis ideal for getting the current date without taking into account the time of day. It isolates the concept of calendar date from time and time zone, making it an ideal choice for birthdays, holidays, or subscription expirations. Using this class makes the code much more readable and self-documenting.
import java.time.LocalDate;LocalDate today = LocalDate.now;
int year = today.getYear;
int month = today.getMonthValue;
If you need to get the full date and time, you should use the class LocalDateTime. It combines date and time information, but, like its brother, does not contain time zone information. This conscious division of responsibility allows the developer to explicitly decide whether he needs to take into account the user's geographic location or work with the device's local time.
One โโof the main advantages is the rich set of methods for manipulating dates. You can easily add days, subtract months, or find next Monday using easy-to-understand methods like java.time is a rich set of methods for manipulating dates. You can easily add days, subtract months, or find next Monday using easy-to-understand methods like plusDays or with. Such operations return a new object, leaving the original unchanged, which completely eliminates side effects.
Use the Instant class to work with UTC timestamps, especially if your application communicates with a server. This guarantees time synchronization regardless of the user's device settings.
Working with dates in the Kotlin language
The language Kotlin has become the de facto standard for development under Android, offering many syntactic improvements that make working with dates even more convenient. Although Kotlin uses the same classes from java.time Under the hood, it provides feature extensions and a more concise syntax for creating and formatting temporary objects.
In Kotlin you can get the current date just like in Java, but often developers use helper libraries such as java.time-kotlin or built-in language features to simplify the code. For example, accessing object properties can be done without calling getters, which makes the code cleaner.
import java.time.LocalDateimport java.time.format.DateTimeFormatter
val today = LocalDate.now
val formattedDate = today.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))
Particularly noteworthy are Kotlin's string templates, which allow you to easily embed date values โโin the body of a message to the user. Instead of string concatenation, you can use interpolation, which reduces the likelihood of errors and improves the readability of the code. This is especially useful when generating notifications or headers in the application interface.
In addition, the Kotlin ecosystem offers many third-party libraries that expand the functionality of working with time. Libraries like Kotlinx-Datetime provide multi-platform support, which is critical for projects using Kotlin Multiplatform. They provide a unified logic for working with dates on Android, iOS and web platforms.
โ๏ธ Checking readiness for migration to java.time
Formatting the date to display to the user
Getting the date object is only half the task. More often than not, the end goal is to present this information to the user in an understandable and localized format. For these purposes, the modern stack uses class DateTimeFormatter, which replaced the outdated one SimpleDateFormat.
Class DateTimeFormatter is thread-safe and immutable, which allows it to be instantiated as constants and used throughout the application without worrying about race conditions. You can use predefined formats or define your own patterns using special characters to represent day, month, year and time.
| Pattern Symbol | Description | Output Example |
|---|---|---|
d |
Day of the Month | 5 |
dd |
Day of the Month with leading zero | 05 |
M |
Month number | 11 |
MMMM |
Full month name | November |
yyyy |
Four-digit year | 2026 |
When formatting, it is important to take into account the userโs locale so that the names of months and days of the week are displayed in their native language. To do this, when creating a formatter, you can pass an object Locale, which will automatically adjust the output to the system settings. Ignoring this requirement may result in the user seeing the date in English, even if the application interface is completely Russified.
โ ๏ธ Attention: Never use code strings to format dates in international applications. Always use
DateTimeFormatter.ofLocalizedDateor explicitly specify the locale, otherwise users in different countries will see formats they do not understand (for example, MM/DD/YYYY instead of DD.MM.YYYY).
Compatibility with older versions of Android
Even though modern versions Android support java.time natively, many developers are forced to support devices with API versions lower than 26. For such cases, there is an excellent backport library called ThreeTenABP (Android Backport), which transfers the functionality of JSR-310 to older platforms.
Connecting this library requires minimal effort: just add the dependency to the file build.gradle and call the initialization method in the class Application when the application starts. After this, you will be able to import classes from the package org.threeten.bp instead of the standard java.time, receiving the same powerful API.
// In the file build.gradle (app)dependencies {
implementation'com.jakewharton.threetenabp:threetenabp:1.4.6'
}
// In the Application class
override fun onCreate {
super.onCreate
AndroidThreeTen.init(this)
}
Using a backport ensures that your application will behave predictably on any device, from ancient smartphones to the latest flagships. This eliminates the need to write conditional logic (if/else) to check the OS version and switch between different implementations of working with dates within business logic.
Why should not use Joda-Time?
The Joda-Time library was once a standard, but now it is in support mode and is not being developed. The authors recommend switching to java.time, since Joda-Time is larger and may conflict with new system classes.
Common errors and best practices
When working with temporary data, even experienced developers can make mistakes that only appear in specific conditions. One of the most common problems is ignoring time zones. When you get a date from a server in UTC and display it to the user without converting it to their local time zone, the time can be off by several hours, causing confusion.
Another common mistake is related to testing. Many developers test date logic using their computer's system time. This makes tests unstable: a test that runs today may fail tomorrow due to a date change. To solve this problem, you should use dependency injection and pass the current time as a parameter, which will allow you to replace it with a fixed value in tests.
You should also avoid storing dates as strings in the database. The string representation is format and locale dependent, making sorting and comparison difficult. The best practice is to store time as long (milliseconds since epoch) or use data types specific to your DBMS (for example, INTEGER for Unix time in Room), and convert to a readable format only at the display stage.
Always separate data storage logic (UTC/milliseconds) from display logic (local time/rich text). This will simplify code support and avoid errors with time zones.
FAQ: Frequently asked questions
How to get the current date in string format with one line of code?
In modern versions of Android (API 26+) this can be done using: LocalDate.now.format(DateTimeFormatter.ofPattern("dd.MM.yyyy")). For older versions, you will need to use SimpleDateFormat or the ThreeTenABP library.
What is the difference between LocalDate and LocalDateTime?
LocalDate contains only date information (year, month, day), ignoring the time of day and time zone. LocalDateTime also includes time (hours, minutes, seconds, nanoseconds), but also not tied to a specific time zone.
Why is my month displayed incorrectly (one less)?
This is a classic error when using an outdated class Calendar or Date, where the month numbering starts from zero (January = 0). When using java.time (LocalDate), months are numbered from 1 to 12, which is more intuitive.
How to get the date exactly one week ago?
Using the java.time API, this is done very simply: LocalDate.now.minusWeeks(1). This method returns a new date object, shifted 7 days into the past, keeping the original object unchanged.
Do you need to add permissions to Manifest to work with the date?
No, getting the system time does not require any special permissions (permissions). This is a basic function of the operating system, available to any application without restrictions.