I'm writing a impala udf in c++ which gets week of year when provided with date in yyyyMMdd. But could not seem to find way to convert yyyyMMdd to week of year in c++. In java I can you Calendar, but how to go about it in c++.
TIA
You can just use std::mktime from <ctime>. Example:
std::tm date={};
date.tm_year=2014-1900;
date.tm_mon=9-1;
date.tm_mday=28;
std::mktime(&date);
After the call, date.tm_wday is adjusted (0=Sunday). date.tm_yday is also adjusted.
To get the week into the year, use: (date.tm_yday-date.tm_wday+7)/7
This calculation returns 1 for the first full week (namely, first week with a Sunday in it in the year, including Jan 1 in years that start with Sunday); and 0 for days in the first partial week.
I answered this here, but for the sake of completeness, I will repeat it here too:
Use iso_week.h from howardhinnant.github.io/iso_week.html :
#include <iostream>
#include "iso_week.h"
int main() {
using namespace iso_week;
using namespace std::chrono;
// Get the current time and floor to convert to the sys_days:
auto today = floor<days>(system_clock::now());
// Convert from sys_days to iso_week::year_weeknum_weekday format
auto yww = year_weeknum_weekday{today};
// Print current week number of the year
std::cout << "The current week of " << yww.year() << " is: "
<< yww.weeknum() << std::endl;
// Set any day
auto any_day = 2014_y/9/28;
// Get week of `any_day`
std::cout << "The week of " << any_day.year() << " on `any day` was: "
<< any_day.weeknum() << std::endl;
}
which gives the output:
The current week of 2019 is: W18
The week in 2014 on `any day` was: W09
Use boost::date library.It's simple and easy to use.
Related
How will I get the expiration date of an item, which is based on week code? Whenever I run the code that I made, the program reads the current date and disregards the week code. For example:
Week Code: 2138 (2021 week 38)
Shelf_life : 6 months
CTime weekcode = CTime::GetCurrentTime();
CTimeSpan shelf_no = CTimeSpan(atoi(view->m_pODBCPartsNo->m_shelf_life), 0, 0, 0);
CTime expiration_date = weekcode = shelf_no;
Week code is a date code, for example 2138, year 2021(21) week 38(38). Week 38 is around September 19, 2021 to September 25, 2021.
Now the question is, how will i get the expiration date that is based on week code ? Will I still use "GetCurrentTime" ?
Here's how I would do it using Howard Hinnant's free, open-source, header-only date library:
#include "date/iso_week.h"
#include "date/date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace date;
int weekcode = 2138;
int shelf_life = 6;
iso_week::year y{weekcode / 100 + 2000};
iso_week::weeknum wk(weekcode % 100);
auto prod_date = y/wk/iso_week::wed;
auto exp_date = floor<days>(sys_days{prod_date} + months{shelf_life});
std::cout << "Production date : " << prod_date << '\n';
std::cout << "Expiration date : " << exp_date << '\n';
}
This assumes that you are using ISO week date as the definition of "week number", which is an internationally accepted standard. The program begins by simply decoding weekcode into a year and weeknum. It then uses the iso_week library to create a production date with this year and weeknum. To complete this date, a weekday must be supplied. I've chosen Wednesday since this is the middle of the ISO work week.
auto prod_date = y/wk/iso_week::wed;
The expiration date can then be computed by simply adding 6 months to that date. Note that this addition is done using a chronological computation because product aging is a physical process that does not care that different months have different lengths. Using an "average month" length is adequate.
To do this chronological arithmetic, the production date must first be converted to a chronological date, sys_days. This is simply a count of days since the Unix Time epoch.
auto exp_date = floor<days>(sys_days{prod_date} + months{shelf_life});
The result has a precision finer than days since the average month duration is not an integral number of days. So it must be truncated back to the precision of days to create a date, as opposed to a date-time.
The above program prints out:
Production date : 2021-W38-Wed
Expiration date : 2022-03-23
https://www.timeanddate.com/date/weekday.html computes various facts about a day of the year, for example:
Given an arbitrary date, how can these numbers be computed with the C++20 chrono specification?
This is remarkably easy with the C++20 chrono specification. Below I show a function which inputs an arbitrary date, and prints this information to cout. Though at the time of this writing, the C++20 chrono specification isn't yet shipping, it is approximated by a free, open-source library. So you can experiment with it today, and even include it in shipping applications as long as you adopt C++11 or later.
This answer will take the form of a function:
void info(std::chrono::sys_days sd);
sys_days is a day-precision time_point in the system_clock family. That means it is simply a count of days since 1970-01-01 00:00:00 UTC. The type alias sys_days is new with C++20, but the underlying type has been available since C++11 (time_point<system_clock, duration<int, ratio<86400>>>). If you use the open-source C++20 preview library, sys_days is in namespace date.
The code below assumes function-local:
using namespace std;
using namespace std::chrono;
to reduce verbosity. If you are experimenting with the open-source C++20 preview library, also assume:
using namespace date;
Heading
To output the first two lines is simple:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Just take the date sd and use format with the familiar strftime/put_time flags to print out the date and text. The open-source C++20 preview library hasn't yet integrated the fmt library, and so uses the slightly altered format string "%d %B %Y is a %A\n".
This will output (for example):
26 December 2019 is a Thursday
Additional facts
Common intermediate results computed once
This section of the function is written last, because one doesn't yet know what computations will be needed multiple times. But once you know, here is how to compute them:
year_month_day ymd = sd;
auto y = ymd.year();
auto m = ymd.month();
weekday wd{sd};
sys_days NewYears = y/1/1;
sys_days LastDayOfYear = y/12/31;
We will need the year and month fields of sd, and the weekday (day of the week). It is efficient to compute them once and for all in this manner. We will also need (multiple times) the first and last days of the current year. It is hard to tell at this point, but it is efficient to store these values as type sys_days as their subsequent use is only with day-oriented arithmetic which sys_days is very efficient at (sub-nanosecond speeds).
Fact 1: day number of year, and number of days left in year
auto dn = sd - NewYears + days{1};
auto dl = LastDayOfYear - sd;
cout << "* It is day number " << dn/days{1} << " of the year, "
<< dl/days{1} << " days left.\n";
This prints out the day number of the year, with January 1 being day 1, and then also prints out the number of days remaining in the year, not including sd. The computation to do this is trivial. Dividing each result by days{1} is a way to extract the number of days in dn and dl into an integral type for formatting purposes.
Fact 2: Number of this weekday and total number of weekdays in year
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
auto total_wd = (last_wd - first_wd)/weeks{1} + 1;
auto n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number ", wd) << n_wd << " out of "
<< total_wd << format(" in {:%Y}.\n}", y);
wd is the day of the week (Monday thru Sunday) computed at the top of this article. To perform this computation we first need the dates of the first and last wd's in the year y. y/1/wd[1] is the first wd in January, and y/12/wd[last] is the last wd in December.
The total number of wds in the year is just the number of weeks between these two dates (plus 1). The sub-expression last_wd - first_wd is the number of days between the two dates. Dividing this result by 1 week results in an integral type holding the number of weeks between the two dates.
The week number is done the same way as the total number of weeks except one starts with the current day instead of the last wd of the year: sd - first_wd.
Fact 3: Number of this weekday and total number of weekdays in month
first_wd = y/m/wd[1];
last_wd = y/m/wd[last];
total_wd = (last_wd - first_wd)/weeks{1} + 1;
n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number }", wd) << n_wd << " out of "
<< total_wd << format(" in {:%B %Y}.\n", y/m);
This works just like Fact 2, except we start with the first and last wds of the year-month pair y/m instead of the entire year.
Fact 4: Number of days in year
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
The code pretty much speaks for itself.
Fact 5 Number of days in month
total_days = sys_days{y/m/last} - sys_days{y/m/1} + days{1};
cout << format("* {:%B %Y} has ", y/m) << total_days/days{1} << " days.\n";
The expression y/m/last is the last day of the year-month pair y/m, and of course y/m/1 is the first day of the month. Both are converted to sys_days so that they can be subtracted to get the number of days between them. Add 1 for the 1-based count.
Use
info can be used like this:
info(December/26/2019);
or like this:
info(floor<days>(system_clock::now()));
Here is example output:
26 December 2019 is a Thursday
Additional facts
* It is day number 360 of the year, 5 days left.
* It is Thursday number 52 out of 52 in 2019.
* It is Thursday number 4 out of 4 in December 2019.
* Year 2019 has 365 days.
* December 2019 has 31 days.
Edit
For those who are not fond of the "conventional syntax", there is a complete "constructor syntax" that can be used instead.
For example:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
can be replaced by:
sys_days NewYears = year_month_day{y, month{1}, day{1}};
sys_days first_wd = year_month_weekday{y, month{1}, weekday_indexed{wd, 1}};
sys_days last_wd = year_month_weekday_last{y, month{12}, weekday_last{wd}};
I was trying to make a program that calculated the fee of a membership at a swimming pool. The user would enter a date (the last time a member renewed the membership), and the program would calculate if their membership was overdue or not, using the current date.
The membership is meant to be overdue a week (or another arbitrary time period) before the start of the month they joined in a year's time. For example, if I joined in February 2016, I would have to pay on January 24 2017 or before to make sure the membership is overdue. As soon as it gets to January 25, a month fee should be charged ($15) and as soon as it reaches February 25, two months fee should be charged etc.
However, I do not know how to charge for subsequent months after the first one. For example, paying on February 3 should result in one month overdue but paying on February 26 should be two months but I do not know how to do this.
How can I fix my function because it doesn't seem to work?
E.g. I entered November 15 2016 and it should return 15 since the membership was due on October 24 2017 but it returns 0.
int membershipFine(int joinDay, int joinMonth, int joinYear, int currentDay, int currentMonth, int currentYear)
{
int dueDay[12] = {25, 22, 25, 24, 25, 24, 25, 25, 24, 25, 24, 25}; // the week before the end of each month in days
int correspondingMonth = joinMonth - 2; // finds the element position that corresponds
if (correspondingMonth == -1) // if they joined in january, the array will go to december
{
correspondingMonth = 11;
}
int differenceInMonths = currentMonth - joinMonth + 12 * (currentYear - joinYear);
if (differenceInMonths < 11)
{
return 0;
}
else if ((differenceInMonths == 11) && (joinDay < dueDay[correspondingMonth]))
{
return 0;
}
else if (differenceInMonths == 11)
{
return 15;
}
if (differenceInMonths > 11 && joinDay < dueDay[correspondingMonth]) // not sure about this if and else statement
{
return (differenceInMonths - 11) * 15;
}
else return (differenceInMonths - 10) * 15;
}
The best way to deal with dates and times is to use a library that raises the level of abstraction about integers, to dates and times. Howard Hinnant's free, open-source, header-only library is such a tool.
It has a {year, month, day} class called date::year_month_day that lends itself to year and month arithmetic. One could use this to change the API of membershipFine from taking 6 type-unsafe parameters to just two type-safe parameters:
int
membershipFine(date::year_month_day joinDate, date::year_month_day currentDate);
Your description of the due date appears to say that it is independent of the day of the month of the join date, and that it is 1 year, less 1 week from the first of the month of the join date. If this is true, this can be easily computed like this:
using namespace date;
year_month_day dueDate{
local_days{(joinDate.year()/joinDate.month() + years{1})/1} - weeks{1}};
The expression joinDate.year()/joinDate.month() creates a year_month object, which is just a year and month, neglecting the day-of-the-month from joinDate. I add 1 year to that year_month, which results in another year_month, exactly 1 year later.
To that sum, /1 is appended. This creates a year_month_day corresponding to the first day of the month of the aforementioned year_month.
Now even though year_month_day is great for year and month oriented arithmetic, it is not so great for day and week-oriented arithmetic. The best data structure for that is a {count-of-days} from some epoch. This library has such a data structure called local_days. So I convert to that, subtract 1 week, and then convert back to year_month_day.
All of this (to compute the due date) happens in the lines of code above.
Now I need to compute the fine based on the relationship between currentDate and dueDate. The fine is $0 if currentDate < dueDate, and otherwise is a function of the number of whole months (plus 1) currentDate is beyond dueDate (as I understand your problem statement):
int fine = 0;
if (currentDate >= dueDate)
{
auto differenceInMonths = currentDate.year()/currentDate.month() -
dueDate.year()/dueDate.month();
if (currentDate.day() >= dueDate.day())
++differenceInMonths;
fine = differenceInMonths.count() * 15;
}
The difference in months, neglecting the day-of-the-month, can be computed by converting to year_month objects and subtracting. Now if currentDate.day() < dueDate.day(), this is the correct answer. For example if the difference in months is 1, but the day of the month in currentDate has not yet exceeded the day of the month in dueDate, then we don't want to charge for a second month, else we do. If we do, differenceInMonths is incremented.
Then the fine is simply the differenceInMonths, converted from months to integral, times 15.
<aside> If there are any <chrono> fans out there, the type of differenceInMonths is actually a std::chrono::duration with a period that is exactly the average month. Thus the .count() member function to access the underlying integral value.
I've added some print statements to the above code, and below I show the whole thing put together plus a driver with a few examples:
#include "date/date.h"
#include <iostream>
int
membershipFine(date::year_month_day joinDate, date::year_month_day currentDate)
{
using namespace date;
year_month_day dueDate{
local_days{(joinDate.year()/joinDate.month() + years{1})/1} - weeks{1}};
int fine = 0;
if (currentDate >= dueDate)
{
auto differenceInMonths = currentDate.year()/currentDate.month() -
dueDate.year()/dueDate.month();
if (currentDate.day() >= dueDate.day())
++differenceInMonths;
fine = differenceInMonths.count() * 15;
}
std::cout << "join Date is " << joinDate << '\n';
std::cout << "due Date is " << dueDate << '\n';
std::cout << "current Date is " << currentDate << '\n';
std::cout << "fine is $" << fine << '\n';
return fine;
}
int
main()
{
using namespace date::literals;
std::cout << membershipFine(feb/29/2016, jan/24/2017) << '\n';
std::cout << membershipFine(feb/29/2016, jan/25/2017) << '\n';
std::cout << membershipFine(feb/29/2016, feb/24/2017) << '\n';
std::cout << membershipFine(feb/29/2016, feb/25/2017) << '\n';
}
This outputs:
join Date is 2016-02-29
due Date is 2017-01-25
current Date is 2017-01-24
fine is $0
0
join Date is 2016-02-29
due Date is 2017-01-25
current Date is 2017-01-25
fine is $15
15
join Date is 2016-02-29
due Date is 2017-01-25
current Date is 2017-02-24
fine is $15
15
join Date is 2016-02-29
due Date is 2017-01-25
current Date is 2017-02-25
fine is $30
30
In summary, the use of a library such as this frees you from having to think in terms of ints so you can concentrate on the logic you have to implement in terms of dates and calendars. The result is compact and readable code that is far more likely to be correct.
Update
In the comments below the OP asks about how to parse a date from cin and how to get the current date. There are several options.
Here is how I recommend asking for a date:
date::year_month_day join;
while (true)
{
std::cout << "Enter join date as yyyy-mm-dd: ";
std::cin >> date::parse("%F", join);
if (!std::cin.fail())
break;
std::cin.clear();
std::string garbage;
std::getline(std::cin, garbage);
std::cout << "Please try again.\n";
}
If you prefer to ask for some other format, here is the complete list of parsing flags available for use.
And the OP asks how to get the current date. There are multiple answers. If you are content with the current date in UTC, that is the simplest:
using namespace std::chrono;
using namespace date;
year_month_day today = floor<days>(system_clock::now());
If you want the current date in your local time zone, you need to use "date/tz.h" (requires some installation) and this syntax:
year_month_day today{floor<days>(make_zoned(current_zone(),
system_clock::now()).get_local_time())};
If you want the current date in some time zone other than your current local time zone, that can be done with:
year_month_day today{floor<days>(make_zoned("America/Los_Angeles",
system_clock::now()).get_local_time())};
No matter how you parse your join and today, they can be used like this:
std::cout << membershipFine(join, today) << '\n';
Need a C++ function to find out the date of the first day of week from the week number.
Input : year and week number
Output : date [It should be 1st day of that week number]
e.g :
inputs :
year – 2017, week number – 8
Output: 20th Feb 2017
inputs:
year – 2017, week number – 10
Output: `6th March 2017
Using Howard Hinnant's free, open-source, header-only date library, it can look like this:
#include "date.h"
#include "iso_week.h"
#include <iostream>
int
main()
{
using namespace iso_week::literals;
std::cout << date::year_month_day{2017_y/8_w/mon} << '\n';
std::cout << date::year_month_day{2017_y/10_w/mon} << '\n';
}
which outputs:
2017-02-20
2017-03-06
There are also getters for year, month and day on the year_month_day types, and plenty of formatting options.
Is there a way to get only the no. of weekdays between 2 boost dates.
In the following, I'm only getting calendar days.
date begin_dt(2011,Aug,3);
date end_dt(day_clock::local_day());
days duration=end_dt-begin_dt;
std::cout<<"calendar days between begin & end date are: "<<duration<<std::endl;
Perhaps the simplest way is to run a day_iterator from start to finish:
#include <iostream>
#include <boost/date_time.hpp>
int main()
{
using namespace boost::gregorian;
date begin_dt(2011,Aug,3);
date end_dt(day_clock::local_day());
days duration=end_dt-begin_dt;
std::cout<<"calendar days between begin & end date are:" << duration << '\n';
int cnt=0;
for(day_iterator iter = begin_dt; iter!=end_dt; ++iter)
{
if( iter->day_of_week() != boost::date_time::Saturday
&& iter->day_of_week() != boost::date_time::Sunday)
++cnt;
}
std::cout << "of them " << cnt << " are weekdays\n";
}
You could start substracting the number of days to the next week start, and deleting either 1 or two depending if you're on saturday or before, or sunday. Then, you can divide the rest of the days remaining by 7, multiply that number by 2, and substract to the days. You have to make a case for the remainder too. If it is 6 (saturday), you have to remove one more. Not easy, but you get the idea.