├── .gitignore ├── CHANGES.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── marcinorlowski │ │ └── datetimetemplate │ │ └── demo │ │ └── MainActivity.kt │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img └── demo.png ├── lib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── marcinorlowski │ │ └── datetimetemplate │ │ └── DateTimeTemplate.java │ └── res │ └── values │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | /.idea/sonarlint 7 | /.idea/kotlinc.xml 8 | /.idea/ 9 | .DS_Store 10 | /build 11 | /captures 12 | .externalNativeBuild 13 | *~ 14 | *.bak 15 | *.swp 16 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # DateTimeTemplate for Android # 2 | 3 | ## CHANGELOG ## 4 | 5 | 1.5.0 (2022-11-21) 6 | ================== 7 | * Demo app rewritten in Kotlin. 8 | * Dropped ButterKnife in favor of data binding. 9 | * Updated dependencies to recent versions. 10 | 11 | 1.4.0 (2020-06-04) 12 | ================== 13 | * Updated demo app to use AndroidX 14 | * Updated dependencies to recent versions 15 | 16 | 1.3.1 (2018-03-11) 17 | ================== 18 | * Fixed bug in `format()` not replacing placeholders 19 | 20 | 1.3.0 (2018-03-11) (broken!) 21 | ================== 22 | * Added support for `%Aa%` placeholder 23 | 24 | 1.2.4 (2018-02-23) 25 | ================== 26 | * Added date/time pickers to demo app 27 | * [#10] `%k%` and `%kk%` produced 0 instead of 12 for noon and midnight 28 | 29 | v1.2.3 (2017-07-05) 30 | =================== 31 | * Updated dependencies 32 | 33 | v1.2.2 (2017-05-26) 34 | =================== 35 | * Disabled proguard for the library 36 | 37 | v1.2.1 (2017-05-25) 38 | =================== 39 | * [#6] Fixed proguard config file 40 | 41 | v1.2.0 (2017-05-24) 42 | =================== 43 | * [#2] Fixed `%mm%` producing wrong results 44 | * [#4] Calendar's TZ was not used for localized placeholders (i.e. day names) 45 | 46 | v1.1.0 (2017-03-09) 47 | =================== 48 | * You can now pass `Locale` of your choice to `format()` when needed 49 | 50 | v1.0.1 (2017-03-08) 51 | =================== 52 | * Lowered `minSdk` to `ICE_CREAM_SANDWICH` (`14`) 53 | 54 | v1.0.0 (2017-03-08) 55 | =================== 56 | * First public release 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Release](https://jitpack.io/v/MarcinOrlowski/datetimetemplate.svg)](https://jitpack.io/#MarcinOrlowski/DateTimeTemplate) 2 | ![Downloads](https://jitpack.io/v/MarcinOrlowski/DateTimeTemplate/month.svg) 3 | [![Dependency Status](https://dependencyci.com/github/MarcinOrlowski/DateTimeTemplate/badge)](https://dependencyci.com/github/MarcinOrlowski/DateTimeTemplate) 4 | 5 | DateTimeTemplate 6 | ================ 7 | `DateTimeTemplate` is flexible date/time formatting library with placeholders support. 8 | 9 | ![Demo app](img/demo.png) 10 | 11 | Download demo application APK from [releases](https://github.com/MarcinOrlowski/DateTimeTemplate/releases) 12 | section. Source code in project's `app/` module. 13 | 14 | ## Features ## 15 | 16 | * Easy to use, 17 | * Stable and production ready, 18 | * Localization support, 19 | * Lightweight, 20 | * No extra dependencies, 21 | * Free. 22 | 23 | Installation 24 | ============ 25 | 26 | Edit your master `gradle.build` file and **add** `maven { url 'https://jitpack.io' }` to your current 27 | `repositories` block content (if you use other jitpack hosted libraries, then this step can be skipped): 28 | 29 | allprojects { 30 | repositories { 31 | maven { url 'https://jitpack.io' } 32 | } 33 | } 34 | 35 | Next, edit your **module**'s `build.gradle` and the following dependency: 36 | 37 | compile 'com.github.MarcinOrlowski:datetimetemplate:' 38 | 39 | For recent value of `` consult [library releases](https://github.com/MarcinOrlowski/DateTimeTemplate/releases) 40 | or jitpack 41 | badge: [![Release](https://jitpack.io/v/MarcinOrlowski/datetimetemplate.svg)](https://jitpack.io/#MarcinOrlowski/datetimetemplate) 42 | 43 | 44 | Placeholders 45 | ============ 46 | 47 | Your formatting string can contain anything you like, however certain sequences are considered placeholders, and will be replaced 48 | by corresponding values. Non-placeholders are returned unprocessed 49 | 50 | | Placeholder | Description | 51 | |-------------|-------------| 52 | | %yy% | long year (i.e. "2009") | 53 | | %y% | short year (i.e. "09") | 54 | | %MMM% | long month name (i.e. "January") | 55 | | %MM% | abbreviated month name (i.e. "Jan") | 56 | | %M% | first letter of month name (i.e. "J") | 57 | | %mm% | zero prefixed 2 digit month number ("02" for Feb, "12" for Dec) | 58 | | %m% | month number as is ("2" for Feb, "12" for Dec) | 59 | | %DDD% | full day name (i.e. ""Saturday", "Sunday", "Monday") | 60 | | %DD% | abbreviated day name ("Sat", "Sun", "Mon") | 61 | | %D% | one letter day name ("S", "S", "M") | 62 | | %dd% | zero prefixed 2 digit day number ("01", "27") | 63 | | %d% | day number as is ("1", "27") | 64 | | %dy% | day number of the year (i.e. "250") | 65 | | %dw% | day number in week (i.e. "1" for Monday **if** weeks start on Mondays!) | 66 | | %wm% | week number of current month ("3" for 3rd week) | 67 | | %wy% | week number of the year ("3" for 3rd week, 47 for 47th) | 68 | | %hh% | current hour, zero prefixed, 24hrs clock (i.e. "01", "16") | 69 | | %h% | current hour, 24hrs clock (i.e. "1", "16") | 70 | | %kk% | current hour, zero prefixed, 12hrs clock (i.e. "01", "11") | 71 | | %k% | current hour, 12hrs clock (i.e. "1", "11") | 72 | | %ii% | current minute, zero prefixed (i.e. "01", "35") | 73 | | %i% | current minute, zero prefixed (i.e. "1", "35") | 74 | | %AA% | upper-cased AM/PM marker (i.e. "AM") | 75 | | %A% | upper-cased abbreviated AM/PM marker. "A" for "AM", "P" for "PM" | 76 | | %aa% | lower-cased am/pm marker (i.e. "am") | 77 | | %a% | lower-cased abbreviated AM/PM marker. "a" for "am", "p" for "pm" | 78 | | %Aa% | AM/PM marker with first letter uppercased (i.e. "Am"/"Pm") | 79 | 80 | Examples 81 | ======== 82 | 83 | Format current date, time as it is in `GMT` zone, using 24hrs clock format: 84 | 85 | TimeZone tz = TimeZone.getTimeZone("GMT"); 86 | Calendar c = new GregorianCalendar(tz); 87 | c.setTime(new Date()); 88 | 89 | String formatted = DateTimeTemplate.format(c, "GMT: %DD% %hh%:%ii%"); 90 | 91 | would produce `GMT: Mon 16:25`. 92 | 93 | Format current time as it is in `Pacific Daylight Time` zone (`PDT` is 7 hours behind `GMT`), using 12hrs clock format with 94 | abbreviated AM/PM marker: 95 | 96 | TimeZone tz = TimeZone.getTimeZone("GMT-0700"); 97 | Calendar c = new GregorianCalendar(tz); 98 | c.setTime(new Date()); 99 | 100 | String formatted = DateTimeTemplate.format(c, "Time: %k%:%ii%%a%"); 101 | 102 | would produce `Time: 3:25a`. 103 | 104 | Format current time using device's time zone: 105 | 106 | TimeZone tz = TimeZone.getDefault(); 107 | Calendar c = new GregorianCalendar(tz); 108 | c.setTime(new Date()); 109 | 110 | String formatted = DateTimeTemplate.format(c, ...); 111 | 112 | Formatting using locale of your choice: 113 | 114 | String formatted = DateTimeTemplate.format(cal, "Time: %k%:%ii%%a%", Locale.SIMPLIFIED_CHINESE); 115 | 116 | Contributing 117 | ============ 118 | 119 | Please report any issue spotted using [GitHub's project tracker](https://github.com/MarcinOrlowski/DateTimeTemplate/issues). 120 | 121 | If you'd like to contribute to the this project, 122 | please [open new ticket](https://github.com/MarcinOrlowski/DateTimeTemplate/issues) 123 | **before doing any work**. This will help us save your time in case I'd not be able to accept such changes. But if all is good and 124 | clear then follow common routine: 125 | 126 | * fork the project 127 | * create new branch 128 | * do your changes 129 | * send pull request 130 | 131 | License 132 | ======= 133 | 134 | * Written and copyrighted ©2013-2022 by [Marcin Orlowski](https://marcinorlowski.com) 135 | * DateTimeTemplate is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) 136 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /** ****************************************************************************** 2 | * 3 | * Fonty - Android custom fonts made easy 4 | * 5 | * @author Marcin Orlowski 6 | * @copyright 2013-2022 2022 Marcin Orlowski 7 | * @license https://opensource.org/licenses/Apache-2.0 8 | * @link https://github.com/MarcinOrlowski/DateTimeTemlate 9 | * 10 | ***************************************************************************** **/ 11 | 12 | plugins { 13 | id 'com.android.library' 14 | id 'kotlin-android' 15 | } 16 | 17 | android { 18 | compileSdkVersion rootProject.ext.compileSdkVersion 19 | buildToolsVersion rootProject.ext.buildToolsVersion 20 | 21 | defaultConfig { 22 | applicationId 'com.marcinorlowski.datetimetemplate.demo' 23 | minSdkVersion rootProject.ext.minSdkVersion 24 | targetSdkVersion rootProject.ext.targetSdkVersion 25 | 26 | versionCode rootProject.projectVersionCode 27 | versionName rootProject.projectVersionName 28 | 29 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' 30 | } 31 | 32 | buildTypes { 33 | release { 34 | minifyEnabled false 35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 36 | } 37 | } 38 | 39 | buildFeatures { 40 | viewBinding = true 41 | } 42 | 43 | compileOptions { 44 | sourceCompatibility JavaVersion.VERSION_1_8 45 | targetCompatibility JavaVersion.VERSION_1_8 46 | } 47 | productFlavors { 48 | } 49 | } 50 | 51 | dependencies { 52 | implementation 'androidx.core:core-ktx:1.9.0' 53 | 54 | implementation "com.google.android.material:material:1.8.0-alpha02" 55 | implementation 'androidx.cardview:cardview:1.0.0' 56 | } 57 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Dev\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 13 | 14 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/marcinorlowski/datetimetemplate/demo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.marcinorlowski.datetimetemplate.demo 2 | 3 | import android.app.DatePickerDialog 4 | import android.app.DatePickerDialog.OnDateSetListener 5 | import android.app.Dialog 6 | import android.app.TimePickerDialog 7 | import android.app.TimePickerDialog.OnTimeSetListener 8 | import android.os.Bundle 9 | import android.text.format.DateFormat 10 | import android.view.View 11 | import android.view.inputmethod.InputMethodManager 12 | import android.widget.DatePicker 13 | import android.widget.TimePicker 14 | import androidx.appcompat.app.AppCompatActivity 15 | import androidx.fragment.app.DialogFragment 16 | import com.marcinorlowski.datetimetemplate.DateTimeTemplate 17 | import com.marcinorlowski.datetimetemplate.demo.databinding.ActivityMainBinding 18 | import java.util.* 19 | 20 | /** ****************************************************************************** 21 | * 22 | * DateTimeTemplate 23 | * Flexible date/time formatting library with placeholders support. 24 | * 25 | * @author Marcin Orlowski 26 | * @copyright 2013-2022 Marcin Orlowski 27 | * @license http://www.opensource.org/licenses/mit-license.php MIT 28 | * @link https://github.com/MarcinOrlowski/DateTimeTemplate 29 | * 30 | * *************************************************************************** **/ 31 | 32 | class MainActivity : AppCompatActivity() { 33 | 34 | private lateinit var binding: ActivityMainBinding 35 | 36 | override fun onCreate(savedInstanceState: Bundle?) { 37 | super.onCreate(savedInstanceState) 38 | binding = ActivityMainBinding.inflate(layoutInflater) 39 | setContentView(binding.root) 40 | 41 | mCalendar.time = Date() 42 | mHour = mCalendar[Calendar.HOUR_OF_DAY] 43 | mMinute = mCalendar[Calendar.MINUTE] 44 | mYear = mCalendar[Calendar.YEAR] 45 | mMonth = mCalendar[Calendar.MONTH] 46 | mDay = mCalendar[Calendar.DAY_OF_MONTH] 47 | 48 | binding.update.setOnClickListener { update() } 49 | binding.time.setOnClickListener { pickTime() } 50 | binding.date.setOnClickListener { pickDate() } 51 | } 52 | 53 | private fun update() { 54 | val windowToken = window.decorView.rootView.windowToken 55 | val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager 56 | imm.hideSoftInputFromWindow(windowToken, 0) 57 | binding.root.clearFocus() 58 | binding.text.text = DateTimeTemplate.format(mCalendar, binding.format.text.toString()) 59 | binding.resultCard.visibility = View.VISIBLE 60 | } 61 | 62 | // -------------------------------------------------------------------------------------------------------------------------- 63 | 64 | private fun pickTime() { 65 | TimePickerFragment().show(supportFragmentManager, "timePicker") 66 | } 67 | 68 | class TimePickerFragment : DialogFragment(), OnTimeSetListener { 69 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 70 | return TimePickerDialog(activity, this, mHour, mMinute, DateFormat.is24HourFormat(activity)) 71 | } 72 | 73 | override fun onTimeSet(view: TimePicker, hourOfDay: Int, minute: Int) { 74 | mHour = hourOfDay 75 | mMinute = minute 76 | updateCalendar() 77 | } 78 | } 79 | 80 | // -------------------------------------------------------------------------------------------------------------------------- 81 | 82 | fun pickDate() { 83 | DatePickerFragment().show(supportFragmentManager, "datePicker") 84 | } 85 | 86 | class DatePickerFragment : DialogFragment(), OnDateSetListener { 87 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 88 | return DatePickerDialog(requireActivity(), this, mYear, mMonth, mDay) 89 | } 90 | 91 | override fun onDateSet(view: DatePicker, year: Int, month: Int, day: Int) { 92 | mYear = year 93 | mMonth = month 94 | mDay = day 95 | updateCalendar() 96 | } 97 | } 98 | 99 | companion object { 100 | val mCalendar: Calendar = GregorianCalendar(TimeZone.getDefault()) 101 | protected fun updateCalendar() { 102 | mCalendar[mYear, mMonth, mDay, mHour] = mMinute 103 | } 104 | 105 | protected var mHour = 0 106 | protected var mMinute = 0 107 | protected var mYear = 0 108 | protected var mMonth = 0 109 | protected var mDay = 0 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 16 | 17 | 26 | 27 | 30 | 31 | 34 | 35 |