This question already has answers here:
How can I pad an integer with zeros on the left?
(18 answers)
Adding zero to a single digit number, Is it possible?
(2 answers)
Generate random date of birth
(15 answers)
Closed 5 years ago.
I want to generate random DOB for the given range of year. So I tried the below code
private static String randomDataOfBirth(int yearStart, int yearEnd)
{
GregorianCalendar gc = new GregorianCalendar();
int year = randBetween(yearStart, yearEnd);
gc.set(Calendar.YEAR, year);
int dayOfYear = randBetween(1, gc.getActualMaximum(Calendar.DAY_OF_YEAR));
gc.set(Calendar.DAY_OF_YEAR, dayOfYear);
String date = null;
if(gc.get(Calendar.MONTH) == 0)
{
date = gc.get(Calendar.YEAR) + "-" + 1 + "-" + gc.get(Calendar.DAY_OF_MONTH);
}else
{
date = gc.get(Calendar.YEAR) + "-" + gc.get(Calendar.MONTH) + "-" + gc.get(Calendar.DAY_OF_MONTH);
}
return date;
}
private static int randBetween(int start, int end) {
// TODO Auto-generated method stub
return start + (int)Math.round(Math.random() * (end - start));
}
Main:-
public static void main(String[] args) {
String dob = randomDataOfBirth(1899, 1937);
System.out.println(dob);
}
I can be able to generate the random DOB. But only for the Month and Day, I want to add a prefix '0' for the range from 1 to 9
Month - 01, 02, 03 and ... up to 09
Day - 01, 02, 03 and ... up to 09
Apart from the desired formatting of you date I see some other problems with your code that I think you would want to address:
Assuming you want a usual month number, 01 for January through 12 for December, your handling of the month number is not correct. get(Calendar.MONTH) gives you a 0-based month: 0 for January through 11 for December. Therefore, your code not only will never give you 12 as month and 1 all too often. It will also give you non-existing dates. I have seen 1905-2-31 and 1929-4-31 (because you get 2 for March, which we interpret as February, etc.).
Possibly unimportant, your distribution gives each day in a leap year slightly smaller probablity than other days.
If you can, I suggest you use LocalDate. The class was introduced in Java 8:
private static String randomDataOfBirth(int yearStartInclusive, int yearEndExclusive) {
LocalDate start = LocalDate.ofYearDay(yearStartInclusive, 1);
LocalDate end = LocalDate.ofYearDay(yearEndExclusive, 1);
long longDays = ChronoUnit.DAYS.between(start, end);
int days = (int) longDays;
if (days != longDays) {
throw new IllegalStateException("int overflow; too many years");
}
int day = randBetween(0, days);
LocalDate dateOfBirth = start.plusDays(day);
return dateOfBirth.toString();
}
This gives you evenly distributed, correct dates formatted with 2 digits for month and day-of-month, e.g., 1926-07-05.
If you want to avoid the overflow check, you may of course rewrite your randBetween() to handle longs.
If you cannot use Java 8, you can do something similar with GregorianCalendar and SimpleDateFormat. Counting the exact number of days from lower to upper bound is complicated, though, so you will probably want to stick to your way of picking the date. SimpleDateFormat can still give you correct dates formatted with two digits for month and day. Edit: In your class, declare:
static DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Now just substitute your if-else statement with this:
String date = formatter.format(gc.getTime());
If your randomDataOfBirth() may be accessed from more than one thread, this won’t work since SimpleDateFormat is not thread-safe. If so, each thread should have its own SimpleDateFormat instance.
With Java7 you can try with something like this:
public class DobMaker
{
public String getDOB(int min, int max)
{
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
int year = min + new Random().nextInt(max - min + 1);
calendar.set(Calendar.YEAR, year);
int day = 1+new Random().nextInt(calendar.getActualMaximum(Calendar.DAY_OF_YEAR));
calendar.set(Calendar.DAY_OF_YEAR, day);
return new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime());
}
public static void main(String[] args)
{
DobMaker d = new DobMaker();
System.out.println(d.getDOB(1970, 1980));
System.out.println(d.getDOB(1970, 1971));
System.out.println(d.getDOB(2007, 2016));
}
}
Related
I need to extract the start date and end date from a given year and week and return them as LocalDate:
Example: year / month / week : 2022 / 12 / 49 -> date_begin 05/12/2022 - date_end 11/12/2022 this mean the week 49 of the year 2022 starts from 05/12/2022 and ends on the 11/12/2022. The month is irrelevant, as #rzwitserloot said in the comments. The input is provided in ints int year = 2022 and int week = 49.
How to achieve this?
JSR310-extra had the YearWeek, but the somewhat simpler java.time does not - hence, the simplest way is through the parser even if you don't actually need to parse it:
int weekYear = 2022;
int weekNum = 49;
LocalDate monday = LocalDate.parse(String.format("%04d-W%02d-1", weekYear, weekNum), DateTimeFormatter.ISO_WEEK_DATE);
LocalDate sunday = monday.plusDays(6);
System.out.printf("Week %d of year %d runs from %s to %s\n", weekNum, weekYear, monday, sunday);
NB: The format is e.g. 2022-W49-1; the 1 is for 'monday'. Note that this is weekyears: That means the start date could be in the previous year (e.g. week 1 of certain years starts on december 30th in the previous year), or the end date could be in the next year. This is obvious if you think about it (weeks exist that start in one year and end in the next, and they have to be part of some year's 'week-year' system). Just thought I'd highlight it :)
This solution also works
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.WeekFields;
public class Main {
public static final WeekFields US_WEEK_FIELDS = WeekFields.of(DayOfWeek.SUNDAY, 4);
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2022, 12, 29);
LocalDate date2 = LocalDate.now();
System.out.println(formatDate(date1));
System.out.println(formatDate(date2));
}
public static int getWeek(LocalDate date) {
return date.get(US_WEEK_FIELDS.weekOfWeekBasedYear());
}
public static int getMonth(LocalDate date) {
return date.getMonthValue();
}
public static int getYear(LocalDate date) {
return date.get(US_WEEK_FIELDS.weekBasedYear());
}
public static String formatDate(LocalDate date) {
int week = getWeek(date);
int month = getMonth(date);
int year = getYear(date);
return year + "/" + month + "/" + week;
}
}
When running I get in the console
2022/12/52
2022/12/49
How can i get difference between two selected dates from calendar in Android in days, months and years ? We know all that the months sometimes have 30 days and sometimes 31 days and in February 28 days just every 4 years come 29 days. I want to get the result for example like this: 2 years and 6 months and 24 days.
I try to use LocalDate so this is my code:
public void onSelectedDayChange(#NonNull CalendarView view,
final int year, final int month, final int dayOfMonth) {
textView.setText(String.valueOf(dateDiff(year,month,dayOfMonth)));
}
public Period dateDiff(int year,int month,int day){
final int Day = c.get(Calendar.DAY_OF_MONTH);
final int Month = c.get(Calendar.MONTH);
final int Year = c.get(Calendar.YEAR);
LocalDate localDate1 = LocalDate.of(year,month,day);
LocalDate localDate2 = LocalDate.of(Year,Month,Day);
Period period = Period.between(localDate2,localDate1);
return period;
}
I tested the code but i got wrong result. When i test it with days (02/05/2020) i got 8 days but the difference is 7 days because "April" has 30 days and for the selected day (02/07/2020) i got 2 months and 8 days or the correct answer are 2 months and 7 days.
I try to get first a correct result, if there is a function or a calculation formula to solve this wrong result, this will help me.
Finally i got in result each time something like (P2M8D) that's meaning 2 months and 8 days, or for example (P7D) that's mean 7 days, so how can i change this text to an understood one like 2 months and 8 days or 7 days like the 2 examples because i found problem in result because we have mixed between numbers and characters.
You’re well on the right way.
Follow the Java naming conventions. A variable or parameter name begins with a lower case letter. Always. It’s particularly confusing that you’ve got parameter year and variable Year. This is bound to lead to errors at some point (though this doesn’t seem to be the reason at the moment).
Since you can use LocalDate and Period from java.time, the modern Java date and time API, don’t mix in the poorly designed and outdated Calendar class too, it just complicates things. Your use of LocalDate and Period is basically correct. For getting the current date as a LocalDate use LocalDate.now(ZoneId.systemDefault()) (and we no longer need the uppercase variables, two problems solved in one shot).
I don’t know your date picker, but I suspect that it may use 0-based month numbers: 0 for January through 11 for December. If this is so, you need to add 1 to the month number when creating the LocalDate object.
For a more readable text use the methods of the Period object to get numbers and assemble your own string. A simple example is:
String periodText = "" + period.getYears() + " years "
+ period.getMonths() + " months " + period.getDays() + " days";
You will want to modify it to leave out the years if they are 0 and the months if they are 0. Consider what text you want to write if all the numbers are 0. You will want to write something, or the user will be confused. A further possible refinement will be to use singular of the words if there is exactly 1 (1 year rather than 1 years, etc.). You may look into using a StringJoiner and into writing an auxiliary method that returns a string with a number and the correct form of a noun, for example 1 month but 2 months.
Edit: Code for formatting the Period
Spelling out my suggestion in code, here’s a way to format your Period:
StringJoiner joiner = new StringJoiner(" ");
joiner.setEmptyValue("No time at all");
if (period.getYears() != 0) {
joiner.add(singularOrPlural(period.getYears(), "year", "years"));
}
if (period.getMonths() != 0) {
joiner.add(singularOrPlural(period.getMonths(), "month", "months"));
}
if (period.getDays() != 0) {
joiner.add(singularOrPlural(period.getDays(), "day", "days"));
}
String periodText = joiner.toString();
System.out.println(periodText);
The code is using this auxiliary method:
private static String singularOrPlural(int count, String singular, String plural) {
if (count == -1 || count == 1) {
return "" + count + ' ' + singular;
} else {
return "" + count + ' ' + plural;
}
}
Example outputs:
No time at all
1 day
2 days
1 month
1 month 1 day
2 months
3 years 4 months 5 days
-1 year -1 month -6 days
I can't understand the problem you have with the "wrong result" of the returned period, clarify it better to me if you can.
By the way, you can try this to convert a format like P2M8D to 2 months and 8 days:
public static void main(String[] args) {
int year = 2020, month = 7, day = 2;
int yearDiff = dateDiff(year, month, day).getYears();
int monthDiff = dateDiff(year, month, day).getMonths();
int dayDiff = dateDiff(year, month, day).getDays();
System.out.println("Period -> yyyy:" + yearDiff + " mm:" + monthDiff + " dd:" + dayDiff); // OUTPUT: Period -> yyyy:0 mm:3 dd:7
}
static Period dateDiff(int year, int month, int day) {
Calendar c = Calendar.getInstance();
final int Day = c.get(Calendar.DAY_OF_MONTH);
final int Month = c.get(Calendar.MONTH);
final int Year = c.get(Calendar.YEAR);
LocalDate localDate1 = LocalDate.of(year, month, day);
LocalDate localDate2 = LocalDate.of(Year, Month, Day);
return Period.between(localDate2, localDate1);
}
You have to use getDays, getMonths and getYears methods.
I have a date and a time of a month, for example 31/01/2020 at 14:00:00, this is the last friday of January. How can I get the date for the last Friday of Feb, March, etc.? It should be dynamic because any date can come in, like the second Tuesday of any month and so on.
I am trying with the following with no luck:
LocalDateTime startTime = LocalDateTime.of(2020, 1, 31, 14, 0, 0);
final Calendar calendar = Calendar.getInstance();
calendar.set(startTime.getYear(), startTime.getMonthValue() - 1, startTime.getDayOfMonth(), startTime.getHour(), startTime.getMinute(), startTime.getSecond());
int ordinal = calendar.get(Calendar.WEEK_OF_MONTH);
startTime = startTime.plusMonths(1).with(TemporalAdjusters.dayOfWeekInMonth(ordinal, startTime.getDayOfWeek();
System.out.println(startTime);
it's printing 06/03/2020 (six of march) at 14:00:00 which is wrong and should be 28/02/2020
What am I missing?
Thanks!
As mentioned before, there is some ambiguity in which day of the week of the month you mean, that is, whether you mean the nth day of week or the last nth day of week of the month.
One such example is Monday, February 24th, 2020. It is the fourth and last Monday of February 2020. If you are going to try to determine this for March 2020, which Monday would you pick? The fourth Monday is 23 March, but the last Monday is 30 March.
So apparently, you'll need to distinguish between whether you count forward or backward.
You could, for instance, create a class which represents a certain day of week in a month. This holds three fields: a day-of-week, a position, and whether the position is backwards or not. E.g.
"The second Monday of the month" would have
dayOfWeek = DayOfWeek.MONDAY
position = 2
backwards = false
and
"The last Thursday of the month" would have
dayOfWeek = DayOfWeek.THURSDAY
position = 1
backwards = true
public class WeekdayInMonth {
private final boolean backwards;
private final DayOfWeek dayOfWeek;
private final int position;
private WeekdayInMonth(DayOfWeek dayOfWeek, int position, boolean backwards) {
if (position < 1 || position > 5) {
throw new DateTimeException("Position in month must be between 1 and 5 inclusive");
}
this.dayOfWeek = dayOfWeek;
this.position = position;
this.backwards = backwards;
}
}
We could add factory methods to create WeekdayInMonths from LocalDates:
public static WeekdayInMonth of(LocalDate date) {
int positionInMonth = (date.getDayOfMonth() - 1) / 7 + 1;
return new WeekdayInMonth(date.getDayOfWeek(), positionInMonth, false);
}
private static WeekdayInMonth ofReversing(LocalDate date) {
int lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
int positionInMonth = (lastDayOfMonth - date.getDayOfMonth()) / 7 + 1;
return new WeekdayInMonth(date.getDayOfWeek(), positionInMonth, true);
}
At last, we add a method to get a LocalDate from a YearMonth adjusted to the WeekdayInMonth.
public LocalDate toLocalDate(YearMonth yearMonth) {
// Get a temporal adjuster to adjust a LocalDate to match a day-of-the-week
TemporalAdjuster adjuster = this.backwards ? TemporalAdjusters.lastInMonth(this.dayOfWeek) : TemporalAdjusters.firstInMonth(this.dayOfWeek);
int weeks = this.position - 1;
LocalDate date = yearMonth.atDay(1)
.with(adjuster)
.plusWeeks(this.backwards ? 0 - weeks : weeks);
if (!Objects.equals(yearMonth, YearMonth.from(date))) {
throw new DateTimeException(String.format("%s #%s in %s does not exist", this.dayOfWeek, this.position, yearMonth));
}
return date;
}
Working example
Here a working example at Ideone.
Addendum
I am getting errors like this if the initial date is Jan 1 2020: java.time.DateTimeException: FRIDAY #5 in 2020-02 does not exist. How could I get the previous weekday in case this happens? In this case, how would I get the previous Friday?
Well, then you need to adjust your LocalDate so that it falls within the specified yearmonth. Since every month has at least four day-of-the-weeks and no more than five of them, the difference is never more than a week. We could, after removing the throw new DateTimeException line, simply adjust the returned LocalDate using plusWeeks.
I've forked the abovementioned example and added the toAdjustingLocalDate method.
This solution is kind of complicated but this is because "last of" or "third in" etc aren't always well defined and might not even exists under some conditions. So here is a solution that looks at the initial date and depending of the day of the month it either performs calculations from the start of the month, calculating forward, or the end of the month, calculating backwards.
From my testing it seems to generate the right results and I am sure some code refactoring could be done as well to improve the code but I leave that for the reader.
public static LocalDateTime nextWithSameDayOfMonth(LocalDateTime indate) {
if (indate.getDayOfMonth() < 15) {
return getForStartOfMonth(indate);
}
return getForEndOfMonth(indate);
}
private static LocalDateTime getForEndOfMonth(LocalDateTime indate) {
DayOfWeek dayOfWeek = indate.getDayOfWeek();
LocalDateTime workDate = indate.with(TemporalAdjusters.lastDayOfMonth());
int count = 0;
while (workDate.isAfter(indate)) {
count++;
workDate = workDate.minusWeeks(1);
}
LocalDateTime nextDate = indate.plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
while (nextDate.getDayOfWeek() != dayOfWeek) {
nextDate = nextDate.minusDays(1);
}
return count == 0 ? nextDate : nextDate.minusWeeks(count - 1);
}
private static LocalDateTime getForStartOfMonth(LocalDateTime indate) {
DayOfWeek dayOfWeek = indate.getDayOfWeek();
LocalDateTime workDate = indate.with(TemporalAdjusters.firstDayOfMonth());
int count = 0;
while (workDate.isBefore(indate)) {
count++;
workDate = workDate.plusWeeks(1);
}
LocalDateTime nextDate = indate.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
while (nextDate.getDayOfWeek() != dayOfWeek) {
nextDate = nextDate.plusDays(1);
}
return count == 0 ? nextDate : nextDate.plusWeeks(count - 1);
}
Could you check if the function work for you?
public class FindSameDayNextMonth {
public static void main(String[] args) {
System.out.println("Next month of 'today' is " + FindSameDayNextMonth.getSameDayNextMonth());
}
public static Date getSameDayNextMonth() {
LocalDateTime dt = LocalDateTime.now();
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, dt.getMonthValue()-1);
c.set(Calendar.DAY_OF_MONTH, dt.getDayOfMonth());
c.add(Calendar.MONTH, 1);
return c.getTime();
}
}
The output is
Next month of today is Mon Sep 23 07:18:09 CDT 2019
I want to use the difference method.
It gets a certain date parameter, then calculates the difference between two dates (this and other)
The calculateDate is the way to get the days passed since the Christian counting. I wanted to use it inside the difference method, but I get the following error while trying to compile:
cannot find symbol - variable calculateDate
The difference has to be an absolute value, so I added the Math.abs.
public int difference (Date other) {
return Math.abs(this.calculateDate-other.calculateDate);
}
//computes the day number since the beginning of the Christian counting of years
private int calculateDate (int day, int month, int year)
{
if (month < 3)
{
year--;
month = month + 12;
}
return 365 * year + year/4 - year/100 + year/400 + ((month+1) * 306)/10 + (day - 62);
}
It would be easier to use java.time library instead of writing the day counting code by hand, unless you have a very specific requirement:
private int difference(LocalDate date) {
LocalDate start = LocalDate.of(0, 1, 1); // 1 Jan 0000
return ChronoUnit.DAYS.between(start, date);
}
You can map from java.util.Date to java.time.LocalDate with:
Date date = ...
LocalDate ld = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
How can I calculate the age of a person in year, month, days?
How can I calculate the difference between two dates
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
if(petDetails.getDateOfDeath() != null){
String formatedDateOfDeath = formatter.format(petDetails.getDateOfDeath());
String formateDateOfBirth = formatter.format(petDetails.getDateOfBirth());
}
How can i calculate the age of death from the above. I dont want to use any externallibraries
EDIT: please look at what I've got so far.none of the other threads are like mine. most of them are about date from DOB to today and not in the format im using.
Try this:
public class Age {
public static void main(String[] args) {
Calendar birthDate = new GregorianCalendar(1979, 1, 1);
Calendar deathDate = new GregorianCalendar(2011, 1, 1);
int age = deathDate.get(Calendar.YEAR) - birthDate.get(Calendar.YEAR);
if ((birthDate.get(Calendar.MONTH) > deathDate.get(Calendar.MONTH))
|| (birthDate.get(Calendar.MONTH) == deathDate.get(Calendar.MONTH) && birthDate.get(Calendar.DAY_OF_MONTH) > deathDate
.get(Calendar.DAY_OF_MONTH))) {
age--;
}
System.out.println(age);
}
}
You can solve this without converting them to strings.
since the getDateOfBirth and getDateOfDeath return date objects, you can use the .getTime() method on them which Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.
A fairly simple way of doing this could be
long millisecondsDiff = petDetails.getDateOfDeath().getTime - petDetails.getDateOfBirth().getTime;
You can then either create a new date object directly from this long, or you can do the proper calculations to change milliseconds into days. ie
long age = millisecondsDiff / (1000 * 60* 60 * 24);