Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This is a React Native Date Picker with following main features:

📱&nbsp; Supports iOS, Android and Expo<br>
🕑&nbsp; 3 different modes: Time, Date, DateTime<br>
🕑&nbsp; 4 different modes: Time, Date, DateTime, MonthYear<br>
🌍&nbsp; Various languages<br>
🎨&nbsp; Customizable<br>
🖼&nbsp; Modal or Inlined<br>
Expand Down Expand Up @@ -181,7 +181,7 @@ export default () => {
| `maximumDate` | Maximum selectable date. <br/> Example: `new Date("2021-12-31")` |
| `minimumDate` | Minimum selectable date. <br/> Example: `new Date("2021-01-01")` |
| `minuteInterval` | The interval at which minutes can be selected. | <img src="docs/minute-interval-ios.png" alt="Date picker minute interval IOS" height="120px" /> | <img src="docs/minute-interval-android.png" alt="Date picker minute interval Android" height="120px" /> |
| `mode` | The date picker mode. `"datetime"`, `"date"`, `"time"` | <img src="docs/datetime-mode-ios.png" alt="React native date time picker" height="120px" /><img src="docs/date-mode-ios.png" alt="React native datepicker" height="120px" /><img src="docs/time-mode-ios.png" alt="React native time picker" height="120px" /> | <img src="docs/datetime-mode-android.png" alt="react native date time picker android" height="120px" /><img src="docs/date-mode-android.png" alt="react native datepicker android" height="120px" /><img src="docs/time-mode-android.png" alt="react native time picker android" height="120px" /> |
| `mode` | The date picker mode. `"datetime"`, `"date"`, `"time"`, `"monthyear"` (monthyear: iOS 17.4+, on older iOS falls back to date mode) | <img src="docs/datetime-mode-ios.png" alt="React native date time picker" height="120px" /><img src="docs/date-mode-ios.png" alt="React native datepicker" height="120px" /><img src="docs/time-mode-ios.png" alt="React native time picker" height="120px" /> | <img src="docs/datetime-mode-android.png" alt="react native date time picker android" height="120px" /><img src="docs/date-mode-android.png" alt="react native datepicker android" height="120px" /><img src="docs/time-mode-android.png" alt="react native time picker android" height="120px" /> |
| `locale` | The locale for the date picker. Changes language, date order and am/pm preferences. Value needs to be a <a title="react native datepicker locale id" href="https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html">Locale ID.</a> | <img src="docs/locale-ios.png" alt="React Native Date picker locale language ios" height="120px" /> | <img src="docs/locale-android.png" alt="React Native Date picker locale language android" height="120px" /> |
| `timeZoneOffsetInMinutes` | Timezone offset in minutes (default: device's timezone) |
| `is24hourSource` | Change how the 24h mode (am/pm) should be determined, by device settings or by locale. {'locale', 'device'} (android only, default: 'device') |
Expand Down Expand Up @@ -227,7 +227,7 @@ On iOS the 12/24h preference is determined by the `locale` prop. Set for instanc

### Is it possible to show only month and year?

This is unfortunately not possible due to the limitation in DatePickerIOS. You should be able to create your own month-year picker with for instance https://github.com/TronNatthakorn/react-native-wheel-pick.
Yes. Use `mode="monthyear"` to show a picker that lets users select only month and year. On iOS 17.4+ it uses the native `UIDatePicker.Mode.yearAndMonth`; on older iOS it falls back to the full date picker. On Android it uses the custom wheel pickers with year and month only. The returned date is always the first day of the selected month at midnight.

### Why does the Android app crash in production?

Expand All @@ -253,9 +253,9 @@ const [state, setState] = useState("idle")
<ConfirmButton disabled={state === "spinning"} />
```

## Three different modes
## Four different modes

Here are some more info about the three different picker modes that are available.
Here are some more info about the four different picker modes that are available.

### Date time picker

Expand Down Expand Up @@ -320,6 +320,17 @@ Set mode property to `time` to show the time picker:
/>
```

### Month and year picker

The monthyear mode displays a picker for selecting only month and year (e.g. for credit card expiration). On iOS 17.4+ it uses the native year-and-month picker; on older iOS it falls back to the full date picker. On Android it shows year and month wheels only. The returned date is the first day of the selected month at midnight.

```jsx
<DatePicker
...
mode="monthyear"
/>
```

## About

React Native Date Picker is a cross platform component for iOS and Android. It uses native code from respective platform to get the genuine look and feel the users expect. A strong motivation for creating this picker was the datetime mode on Android. It's quite unique for the platform and avoids two different picker popups, which normally is necessary. Instead, this datetime mode requires fewer user actions and enables a great user-experience.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public ArrayList<WheelType> getVisibleWheels() {
visibleWheels.add(WheelType.DATE);
break;
}
case monthyear: {
visibleWheels.add(WheelType.YEAR);
visibleWheels.add(WheelType.MONTH);
break;
}
}
if((mode == Mode.time || mode == Mode.datetime) && state.derived.usesAmPm()){
visibleWheels.add(WheelType.AM_PM);
Expand All @@ -57,6 +62,9 @@ public ArrayList<WheelType> getOrderedVisibleWheels() {
}

private ArrayList<WheelType> getOrderedWheels() {
if (state.getMode() == Mode.monthyear) {
return LocaleUtils.getMonthYearWheelOrder(state.getLocale());
}
String dateTimePatternOld = LocaleUtils.getDateTimePattern(state.getLocale());
String dateTimePattern = dateTimePatternOld.replaceAll("\\('(.+?)'\\)","\\${$1}")
.replaceAll("'.+?'","")
Expand Down Expand Up @@ -105,7 +113,7 @@ public boolean usesAmPm(){
}

public boolean hasOnly2Wheels(){
return state.getMode() == Mode.time && !usesAmPm();
return (state.getMode() == Mode.time && !usesAmPm()) || state.getMode() == Mode.monthyear;
}


Expand Down
23 changes: 23 additions & 0 deletions android/src/main/java/com/henninghall/date_picker/LocaleUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
import android.content.res.Resources;
import android.os.Build;

import com.henninghall.date_picker.models.WheelType;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Locale;

public class LocaleUtils {
Expand Down Expand Up @@ -44,6 +47,26 @@ public static String getDatePattern(Locale locale) {
.trim();
}

/**
* Returns wheel order for month-year mode based on locale.
* Uses the date pattern to determine if year or month comes first.
*/
public static ArrayList<WheelType> getMonthYearWheelOrder(Locale locale) {
String pattern = getDatePattern(locale);
int yearPos = pattern.indexOf('y');
int monthPos = pattern.indexOf('M');
if (monthPos < 0) monthPos = pattern.indexOf('L');
ArrayList<WheelType> order = new ArrayList<>();
if (yearPos >= 0 && (monthPos < 0 || yearPos < monthPos)) {
order.add(WheelType.YEAR);
order.add(WheelType.MONTH);
} else {
order.add(WheelType.MONTH);
order.add(WheelType.YEAR);
}
return order;
}

static String getDateTimePattern(Locale locale) {
DateFormat format = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, locale);
return ((SimpleDateFormat) format).toLocalizedPattern().replace(",", "");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.henninghall.date_picker.models;

public enum Mode {
date, time, datetime
date, time, datetime, monthyear
}
24 changes: 24 additions & 0 deletions android/src/main/java/com/henninghall/date_picker/ui/Wheels.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,23 @@ Wheel getWheel(WheelType type){
}

String getDateTimeString(int daysToSubtract) {
if (state.getMode() == Mode.monthyear) {
return getMonthYearDateString() + " 00:00";
}
return getDateString(daysToSubtract) + " " + getTimeString();
}

private String getMonthYearDateString() {
ArrayList<Wheel> wheels = getOrderedVisibleWheels();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < wheels.size(); i++) {
if (i != 0) sb.append(" ");
sb.append(wheels.get(i).getValue());
}
sb.append(" 1");
return sb.toString();
}

private String getDateModeString(int daysToSubtract) {
ArrayList<Wheel> wheels = getOrderedVisibleWheels();
StringBuilder sb = new StringBuilder();
Expand All @@ -104,6 +118,9 @@ private String getDateString(int daysToSubtract){
if(state.getMode() == Mode.date ){
return getDateModeString(daysToSubtract);
}
if (state.getMode() == Mode.monthyear) {
return getMonthYearDateString();
}
return dayWheel.getValue();
}

Expand Down Expand Up @@ -170,10 +187,17 @@ private String getDateFormatPattern(){
+ wheels.get(1).getFormatPattern() + " "
+ wheels.get(2).getFormatPattern();
}
if (state.getMode() == Mode.monthyear) {
return wheels.get(0).getFormatPattern() + " "
+ wheels.get(1).getFormatPattern() + " d HH:mm";
}
return dayWheel.getFormatPattern();
}

public String getFormatPattern() {
if (state.getMode() == Mode.monthyear) {
return this.getDateFormatPattern();
}
return this.getDateFormatPattern() + " "
+ hourWheel.getFormatPattern() + " "
+ minutesWheel.getFormatPattern()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public ArrayList<String> getValues() {

@Override
public boolean visible() {
return state.getMode() == Mode.date;
return state.getMode() == Mode.date || state.getMode() == Mode.monthyear;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private int getStartYear() {

@Override
public boolean visible() {
return state.getMode() == Mode.date;
return state.getMode() == Mode.date || state.getMode() == Mode.monthyear;
}

@Override
Expand Down
2 changes: 0 additions & 2 deletions examples/Rn071/.bundle/config

This file was deleted.

4 changes: 0 additions & 4 deletions examples/Rn071/.eslintrc.js

This file was deleted.

63 changes: 0 additions & 63 deletions examples/Rn071/.gitignore

This file was deleted.

1 change: 0 additions & 1 deletion examples/Rn071/.node-version

This file was deleted.

7 changes: 0 additions & 7 deletions examples/Rn071/.prettierrc.js

This file was deleted.

1 change: 0 additions & 1 deletion examples/Rn071/.ruby-version

This file was deleted.

1 change: 0 additions & 1 deletion examples/Rn071/.watchmanconfig

This file was deleted.

6 changes: 0 additions & 6 deletions examples/Rn071/Gemfile

This file was deleted.

98 changes: 0 additions & 98 deletions examples/Rn071/Gemfile.lock

This file was deleted.

Loading
Loading