{"id":16539,"date":"2022-05-14T09:00:00","date_gmt":"2022-05-14T09:00:00","guid":{"rendered":"https:\/\/phrase.com\/blog\/?p=16539"},"modified":"2022-09-24T21:32:33","modified_gmt":"2022-09-24T21:32:33","slug":"localized-date-time-android","status":"publish","type":"post","link":"https:\/\/phrase.com\/blog\/posts\/localized-date-time-android\/","title":{"rendered":"How to Localize Date and Time Formats in Android"},"content":{"rendered":"<p>In today&#8217;s ever-growing global market for mobile apps, making your app ready to support different languages and cultures from the start is key for organic growth. With Google Play being responsible for <a href=\"https:\/\/www.businessofapps.com\/data\/app-statistics\/\">111.3B downloads<\/a> in 2021, it only makes sense to implement <a href=\"https:\/\/phrase.com\/blog\/posts\/best-practices-for-android-localization-revisited-and-expanded\/\">Android localization<\/a> for your app to look and feel native to users in different corners of the world.<br \/>\nThis goes for date and time formats, too. From the order of days and months in dates, and how hours and minutes in the time are separated, to displaying dates in various long or short formats\u2014date and time information can vary greatly across markets.<br \/>\nTo help you get it right from the get-go, this tutorial outlines best practices for displaying date and time formats to Android users based on their time zone and locale. We&#8217;ll build a news feed application using localized timestamps and learn more about standardized times, handling time zones, absolute and relative dates, and formatting time based on locale.<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_69_1 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Overview<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/phrase.com\/blog\/posts\/localized-date-time-android\/#what-classes-and-libraries-should-you-use\" title=\"What classes and libraries should you use?\">What classes and libraries should you use?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/phrase.com\/blog\/posts\/localized-date-time-android\/#standardized-time\" title=\"Standardized time\">Standardized time<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/phrase.com\/blog\/posts\/localized-date-time-android\/#coordinated-universal-time-utc\" title=\"Coordinated Universal Time (UTC)\">Coordinated Universal Time (UTC)<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/phrase.com\/blog\/posts\/localized-date-time-android\/#building-a-demo-app\" title=\"Building a demo app\">Building a demo app<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/phrase.com\/blog\/posts\/localized-date-time-android\/#internationalizing-dates\" title=\"Internationalizing dates\">Internationalizing dates<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/phrase.com\/blog\/posts\/localized-date-time-android\/#handling-relative-dates\" title=\"Handling relative dates\">Handling relative dates<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/phrase.com\/blog\/posts\/localized-date-time-android\/#wrapping-up-our-tutorial-on-localizing-android-date-and-time-formats\" title=\"Wrapping up our tutorial on localizing Android date and time formats\">Wrapping up our tutorial on localizing Android date and time formats<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"what-classes-and-libraries-should-you-use\"><\/span>What classes and libraries should you use?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>There are many libraries and in-built classes to choose from to manipulate time formats on your Android application: <a href=\"https:\/\/github.com\/JodaOrg\/joda-time\"><code>joda-time<\/code><\/a>, <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/11\/docs\/api\/java.base\/java\/util\/Date.html\"><code>java.util.Date<\/code><\/a>, <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/11\/docs\/api\/java.base\/java\/util\/Calendar.html\"><code>java.util.Calendar<\/code><\/a>, <code>GregorianCalendar<\/code>, and <code>java.text.SimpleDateFormat<\/code>. However, we won&#8217;t use any of them as most of them are mutable, not thread-safe, and their APIs are inconsistent.<br \/>\nInstead, we&#8217;ll use the <code>java.time<\/code> API built into Java 8. The Java 8 Date\/Time APIs are immutable, thread-safe, and follow consistent date and time models; <code>java.time<\/code> also comes with a lot of utility methods that can handle time zone logic.<br \/>\nStill, when you try to use these newer APIs, Android Studio will &#8220;confront&#8221; you with a warning:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17765\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-studio-warning.png\" alt=\"Android Studio warning about using an Android version lower than 26 | Phrase\" width=\"1018\" height=\"355\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-studio-warning.png 1018w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-studio-warning-300x105.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-studio-warning-768x268.png 768w\" sizes=\"(max-width: 1018px) 100vw, 1018px\" \/><br \/>\nThe modern <code>java.time<\/code> APIs are only available for Android versions greater than or equal to 26. If you run it on a version lower than 26, your app will crash, throwing a <code>NoClassDefFoundError<\/code> exception, but we can work around this crash.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb <\/em>If the minimum SDK version for your app is above 25 (~ 60% of devices), you can skip the next step..Making Java 8 APIs Backwards Compatible<br \/>\nWith the help of <a href=\"https:\/\/developer.android.com\/studio\/write\/java8-support\">desugaring<\/a>, lower Android versions can still work with newer Java APIs. Desugaring enables you to include the latest APIs in apps that support older versions of Android. To enable desugaring for your app, follow these steps:<\/p>\n<ul>\n<li>Update the Android Plugin version to <code>4.0.0<\/code> or higher.<\/li>\n<li>In the <code>build.gradle<\/code> file of your app&#8217;s module, make the following changes:<\/li>\n<\/ul>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">android {\n  defaultConfig {\n  \/\/ Required when setting minSdkVersion to 20 or lower\n  multiDexEnabled = true\n  }\n  compileOptions {\n  \/\/ Flag to enable support for the new language APIs\n  coreLibraryDesugaringEnabled = true\n  \/\/ Sets Java compatibility to Java 8\n  sourceCompatibility = JavaVersion.VERSION_1_8\n  targetCompatibility = JavaVersion.VERSION_1_8\n  }\n}\ndependencies {\n  coreLibraryDesugaring(\"com.android.tools:desugar_jdk_libs:1.1.5\")\n}\n<\/pre>\n<ul>\n<li>Rebuild the project.<\/li>\n<\/ul>\n<p>You should now be able to work with newer Java APIs on an older Android version.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb <\/em>Adding <code>java.time<\/code> desugaring adds about 400 KB to your Android Package (APK) size.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"standardized-time\"><\/span>Standardized time<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Imagine the following use case: A global news company, based out of London, is publishing news articles that users consume via an Android app. The company submits an article at 5 pm on 15th January (London time). Most app users are located in the USA and Japan. On both sides, users expect to see an article timestamp in their local date and time format instead of London time (12 pm, 15 January, i.e. 2 am, 16 January). The matter can get even more complex if users are spread all over the world in different time zones.<br \/>\nTo solve the issue, the backend must send news articles with a standardized timestamp that clients (Android) can use and convert into the local time format depending on the user&#8217;s time zone.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"coordinated-universal-time-utc\"><\/span>Coordinated Universal Time (UTC)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><a class=\"c-link\" tabindex=\"-1\" href=\"https:\/\/en.wikipedia.org\/wiki\/Coordinated_Universal_Time\" target=\"_blank\" rel=\"noopener noreferrer\" data-stringify-link=\"https:\/\/en.wikipedia.org\/wiki\/Coordinated_Universal_Time\" data-sk=\"tooltip_parent\" data-remove-tab-index=\"true\">Coord<\/a><a class=\"c-link\" tabindex=\"-1\" href=\"https:\/\/en.wikipedia.org\/wiki\/Coordinated_Universal_Time\" target=\"_blank\" rel=\"noopener noreferrer\" data-stringify-link=\"https:\/\/en.wikipedia.org\/wiki\/Coordinated_Universal_Time\" data-sk=\"tooltip_parent\" data-remove-tab-index=\"true\">inated Universal Time (UTC)<\/a> is the global standard for regulating clocks and times, with time zones around the world expressed using either positive or negative offsets from the UTC. There are <a href=\"https:\/\/www.utctime.net\">many standard ways<\/a> of representing UTC, but we&#8217;ll highlight the two most common formats here:<\/p>\n<ul>\n<li><strong>Unix-Epoch<\/strong>: the number of seconds that have elapsed since 00:00:00 UTC on January 1, 1970, excluding leap seconds; for example, the UTC of January 31, 2022, 17:55:50, is represented as &#8220;1643651750.&#8221;<\/li>\n<li><strong>ISO 8601<\/strong>: a string used to represent the UTC; for example, the UTC of January 32, 2022, 17:55:50, is represented as &#8220;2022-01-31T17:55:50Z,&#8221; where the Z represents a zero UTC offset.<\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"building-a-demo-app\"><\/span>Building a demo app<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Currently, we have a news app that displays a list of news articles fetched from <a href=\"https:\/\/newsapi.org\/docs\">News API<\/a>. Each article contains an image, a headline, as well as a timestamp corresponding to when the article is published. We&#8217;ll use the <code>java.time<\/code> API to internationalize and localize the timestamp into something more intuitive and familiar to our app users across the globe.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb <\/em>You can get the starting code for the app on <a href=\"https:\/\/github.com\/PhraseApp-Blog\/date-time-i18n-android\/tree\/starting_point\">GitHub.<\/a><\/p>\n<div><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17756\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-1.png\" alt=\"A news app that uses java.time APIs | Phrase\" width=\"300\" height=\"674\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-1.png 456w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-1-134x300.png 134w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/div>\n<p>The News API endpoint returns a <code>json<\/code> file consisting of a list of articles:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-highlight=\"7\">articles\": [\n {\n  \"title\": \"Georgia prosecutor asks FBI for security assistance following Trump comments at Texas rally - The Washington Post\",\n  \"description\": \"In a letter Sunday, Fulton County District Attorney Fani Willis pointed to Trump's characterization of prosecutors as \u201cracist\u201d and \u201cmentally sick.\u201d\",\n  \"url\": https:\/\/www.washingtonpost.com\/politics\/2022\/01\/31\/willis-fbi-help-trump-comments\/,\n  \"urlToImage\":https:\/\/www.washingtonpost.com\/wp-apps\/imrs.php?src=https:\/\/arc-anglerfish-washpost-prod-washpost.s3.amazonaws.com\/public\/2INRWAECT4I6ZFI4DYGMG4R6KM.jpg&amp;w=1440,\n  \"publishedAt\": \"2022-01-31T16:27:23Z\",\n  \"content\": \"Security concerns were escalated this weekend by the rhetoric of former President Trump at a public event in Conroe, Texas that was broadcast and covered by national media outlets and shared widely o\u2026 [+2539 chars]\"},\n       ...\n ]\n<\/pre>\n<p>Note that each article item consists of a key called <code>publishedAt<\/code>, which represents the UTC in the ISO 8601 format. At the moment, we&#8217;re displaying the <code>publishedAt<\/code> time directly as is it in the <code>bind<\/code> method of the <code>NewsRecyclerAdapter.kt<\/code> file.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">fun bind(article: Article) {\n  with(containerView) {\n    \/\/ Sets the text for the TextView\n    textview_date_time.text = article.publishedAt\n    textview_description.text = article.description\n      ...\n\t}\n }\n<\/pre>\n<p>The first step would be to convert the UTC into the user&#8217;s time zone. Using the <code>java.time<\/code> API, make the following changes to the <code>NewsRecyclerAdapter.kt<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">...\nimport java.time.Instant\nimport java.time.LocalDate\nimport java.time.ZoneId\nimport java.time.ZonedDateTime\nclass NewsRecyclerAdapter() {\n...\n    fun bind(article: Article) {\n\twith(containerView) {\n\tval timestampInstant = Instant.parse(article.publishedAt)\n        val articlePublishedZonedTime = ZonedDateTime.ofInstant(timestampInstant, ZoneId.systemDefault())\n        textview_date_time.text = articlePublishedZonedTime.toString()\n...\n    }\n}\n<\/pre>\n<p><code>Instant.parse(article.publishedAt)<\/code> takes in the UTC string as a parameter and returns a Java Time Instant object. The Java Instant class represents a time passed in seconds since the origin (epoch) of <code>1970-01-01T00:00:00Z<\/code>. We pass this and the user&#8217;s time zone using <code>ZoneId.systemDefault()<\/code>\u00a0 as a parameter in the <code>ZonedDateTime.ofInstant()<\/code> method, which returns an object of the <code>ZonedDateTime<\/code> type. Finally, we convert <code>articlePublishedZonedTime<\/code> to a string and set it to TextView.<br \/>\nWe have now successfully converted a UTC ISO 8601 string into the user&#8217;s time zone in the same format.<br \/>\nThis is what a user from New York, US, would see:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17758\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-2.png\" alt=\"An app screen representing the user's time in the ISO 8601 format | Phrase\" width=\"300\" height=\"674\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-2.png 456w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-2-134x300.png 134w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n<div>Users from Berlin, Germany, get the following screen displayed:<\/div>\n<div><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17759\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-3.png\" alt=\"App screen representing the user's time in the ISO 8601 format | Phrase\" width=\"300\" height=\"674\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-3.png 456w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-3-134x300.png 134w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/div>\n<h2><span class=\"ez-toc-section\" id=\"internationalizing-dates\"><\/span>Internationalizing dates<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>ISO 8601 isn&#8217;t really the most human-readable format you can show to an app user. This representation is far from natural language and hardly provides a good user experience. To change that, we&#8217;ll internationalize the date according to the user&#8217;s set locale and display it.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb <\/em>To know more about internationalizing Dates in Android, read our <a href=\"https:\/\/phrase.com\/blog\/posts\/internationalizing-jetpack-compose-android-apps\/#Internationalizing_dates\">Deep Dive on Internationalizing Jetpack Compose Android Apps<\/a>.<br \/>\nMake the following changes to the <code>NewsRecyclerAdapter.kt<\/code> file.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">val timestampInstant = Instant.parse(article.publishedAt)\nval articlePublishedZonedTime = ZonedDateTime.ofInstant(timestampInstant, ZoneId.systemDefault())\nval dateFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(MEDIUM)\ntextview_date_time.text = articlePublishedZonedTime.format(dateFormatter)\n<\/pre>\n<p>We&#8217;ve used <code>java.time<\/code>&#8216;s <code>DateTimeFormatter<\/code> to format <code>articlePublishedZonedTime<\/code> from ISO 8601 into a localized date and time in a string depending on the user&#8217;s locale settings.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb <\/em>You can also use FormatStyle.LONG, FormatStyle.FULL, or FormatStyle.MEDIUM for a more detailed representation of date and time information formatted based on the user&#8217;s set locale.<br \/>\nUsers located in New York\u2014Eastern Time (ET) zone\u2014get to see the screen below:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17760\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-4.png\" alt=\"News feed displayed to a user from New York, US (Eastern Time) | Phrase\" width=\"300\" height=\"674\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-4.png 456w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-4-134x300.png 134w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><br \/>\nHere is what the news feed looks like for users in Berlin\u2014Central European Time (CET):<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17761\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-5.png\" alt=\"News feed displayed to a user from Berlin (CET) | Phrase\" width=\"300\" height=\"674\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-5.png 456w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screen-5-134x300.png 134w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n<h2><span class=\"ez-toc-section\" id=\"handling-relative-dates\"><\/span>Handling relative dates<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>While developing your app, you may also need to display relative dates, e.g., &#8220;today&#8221; or &#8220;yesterday&#8221; instead of absolute dates. Recent relative dates are easier to understand for most users.<br \/>\nTo make the use case clearer in the context of our news app, we&#8217;ll use relative dates for articles that were published either today or yesterday.<br \/>\nIn all articles published more than two days ago, we&#8217;d like to display the absolute date.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb <\/em>Relative dates are relative to the user&#8217;s time zone and not the UTC (zero offset) time zone.<br \/>\nTo do this, implement the following changes in the same <code>NewsRecyclerAdapter.kt<\/code> file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">import java.time.Instant\nimport java.time.LocalDate\nimport java.time.ZoneId\nimport java.time.ZonedDateTime\nimport java.time.format.DateTimeFormatter\nimport java.time.temporal.ChronoUnit.DAYS\nimport java.time.format.FormatStyle.MEDIUM\n...\nfun bind(article: Article) {\n  val timestampInstant = Instant.parse(article.publishedAt)\n  val articlePublishedZonedTime = ZonedDateTime.ofInstant(timestampInstant, ZoneId.systemDefault())\n  val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(MEDIUM)\n  val currentTimestamp = Instant.now()\n  \/\/ Get current Instant\n  val currentZonedTime = ZonedDateTime.ofInstant(currentTimestamp, ZoneId.systemDefault())\n  \/\/Convert current Instant to local time zone\n  val gapInDays = articlePublishedZonedTime.toLocalDate().until(currentZonedTime, DAYS)\n  \/\/Find difference in current and published date of article\n  val finalDate = when(gapInDays){\n                    0L -&gt; context.getString(R.string.today)\n                    1L -&gt; context.getString(R.string.yesterday)\n                    else -&gt; articlePublishedZonedTime.format(dateFormatter)\n                }\n   textview_date_time.text = finalDate\n   ...\n<\/pre>\n<p>We use <code>Instant.now()<\/code> to get the current Instant (timestamp) and then pass it along with the user&#8217;s time zone Id in the <code>ZonedDateTime.ofInstant(currentTimestamp, ZoneId.systemDefault())<\/code> method, which returns a <code>ZonedDateTime<\/code>.<br \/>\nNow we compare the <code>currentZonedTime<\/code> and <code>articlePublishedZonedTime<\/code> using <code>articlePublishedZonedTime.toLocalDate().until(currentZonedTime, ChronoUnit.DAYS)<\/code>, which returns the difference in days in Long between the two <code>ZonedDateTime<\/code>s.<br \/>\nWe use this <code>gapInDays<\/code> to find out the corresponding time in string.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb <\/em>Use <code>context.getString()<\/code> instead of hardcoding &#8220;today&#8221; or &#8220;yesterday&#8221; directly as we want to dynamically load the relevant string respecting the user&#8217;s locale settings.<br \/>\nNow add the above string references to the default <code>strings.xml<\/code> file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">&lt;resources&gt;\n &lt;string name=\"today\"&gt;Today&lt;\/string&gt;\n &lt;string name=\"yesterday\"&gt;Yesterday&lt;\/string&gt;\n&lt;\/resources&gt;\n<\/pre>\n<p>We also want to add support in our news app for the <code>de-DE<\/code> locale. To do this, add a new <code>strings.xml<\/code> file for <code>de_DE<\/code> locale and add values for the same keys in German.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">&lt;resources&gt;\n &lt;string name=\"today\"&gt;Heute&lt;\/string&gt;\n &lt;string name=\"yesterday\"&gt;Gestern&lt;\/string&gt;\n&lt;\/resources&gt;\n<\/pre>\n<p>Now let&#8217;s take a look at the app screens for users browsing from NewYork (ET) and Berlin (CET):<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-17762\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screens-relative-dates.jpeg\" alt=\"Android news app screens displaying relative dates | Phrase\" width=\"600\" height=\"660\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screens-relative-dates.jpeg 931w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screens-relative-dates-273x300.jpeg 273w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/07\/android-news-app-screens-relative-dates-768x845.jpeg 768w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><br \/>\nBoth users see the same news articles. However, there are quite some differences in the way data is displayed on both sides. With both absolute and relative dates formatted and translated depending on the user&#8217;s locale and time zone, we provide a unique user experience for everyone regardless of location and language.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb <\/em>The final code for the app can be found on <a href=\"https:\/\/github.com\/PhraseApp-Blog\/date-time-i18n-android\">Github<\/a>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"wrapping-up-our-tutorial-on-localizing-android-date-and-time-formats\"><\/span>Wrapping up our tutorial on localizing Android date and time formats<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In this tutorial, we learned about standardized time formats, leveraging various <code>java.time<\/code> APIs to convert the UTC into the user&#8217;s time zone and format it depending on the user&#8217;s locale.\u00a0 By building a news feed app, in which we displayed relative and absolute dates that take the user&#8217;s locale and time zone into account, we&#8217;ve managed to deliver a distinctive app experience to all users across the globe.<br \/>\nAs soon as you\u2019ve got your app ready for localization, let your team of translators work with Phrase. The fastest, leanest, and most reliable localization solution on the market will help you streamline the Android localization process with everything you need to reach a global user base. Sign up for a <a href=\"https:\/\/eu.phrase.com\/idm-ui\/signup\">free 14-day trial<\/a>\u00a0and let the team know any questions you might have.<br \/>\nIf you want to drill down on Android internationalization even more, we suggest the following guides:<\/p>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/android-app-development-tutorial-multi-language-support\/\">Key Dos &amp; Don\u2019ts of Developing Global-Ready Android Apps<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/quick-guide-android-internationalization-i18n\/\">Android Studio Tutorial on Internationalizing Android Apps<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/internationalizing-jetpack-compose-android-apps\/\">A Deep Dive Into Internationalizing Jetpack Compose Android Apps<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Date and time can vary greatly across markets. Learn how to make your Android app support date and time formats for users around the world.<\/p>\n","protected":false},"author":61,"featured_media":2612,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_stopmodifiedupdate":true,"_modified_date":"","_searchwp_excluded":"","footnotes":""},"categories":[40],"class_list":["post-16539","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-localization"],"acf":[],"_links":{"self":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/16539"}],"collection":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/users\/61"}],"replies":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/comments?post=16539"}],"version-history":[{"count":4,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/16539\/revisions"}],"predecessor-version":[{"id":86272,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/16539\/revisions\/86272"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media\/2612"}],"wp:attachment":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media?parent=16539"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/categories?post=16539"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}