InfoPath (XPath) days remaining of year [closed] - xpath

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I am currently working on a form in InfoPath where users enter a specific date in a field.
I then want a formula to calculate how many days that remain of the year. I also want to value each day to a cost. Say each day cost 2$ and the entered date is December 29th. I then want the function to return "price: 4$"

XPath 2.0 has an awful lot of date/time functions:
To get the days between the last day of 2012 and the current day, you can use:
days-from-duration(date("2012-12-31") - current-date() )
If you have an user inputed date $user-date you need to replace current-date() with that $user-date and to construct a date object for the last december day in that year, which you can do like:
days-from-duration(date(concat(year-from-date($user-date), "-12-31")) - $user-date )
(or use date($user-date), if $user-date is a string)
And to get the final price string use:
concat("price: ", 2 * days-from-duration(date(concat(year-from-date($user-date), "-12-31")) - $user-date ), "$")
XPath 1.0:
Without date function you need to do all these stupid calculation by hand.
You need a map mapping the days from each month to the end of the year. Then you can do Map[$month] - $day. (Or use a map mapping the months to the days to the beginning of the year and subtract that from 365, what I do, since I have that map already lying around)
Now XPath 1.0 does not have maps, but you can simulate one with a string:
365 - substring-before(substring-after( "1:00, 2:31, 3:59, 4:90, 5:120, 6:151, 7:181, 8:212, 9:243, 10:273, 11:304, 12:334, 13:365", concat($month, ":")), ",") - $day
This works for every non leap year.
For a leap year, you just use 366 and add 1 to each month after february:
366 - substring-before(substring-after( "1:00, 2:31, 3:60, 4:91, 5:121, 6:152, 7:182, 8:213, 9:244, 10:274, 11:305, 12:335, 13:366", concat($month, ":")), ",") - $day
To detect the leap year you could do some modulo calculation, it is probably easier to just use a map of all leap years:
concat("0", substring-before(substring-after("...,2000:1,2004:1,2008:1,2012:1,2016:1,...", concat($year, ":")), ",")) * 1
this returns 1 if the year is a leap year in the range
Then put it all together:
( 365 - substring-before(substring-after( "1:00, 2:31, 3:59, 4:90, 5:120, 6:151, 7:181, 8:212, 9:243, 10:273, 11:304, 12:334, 13:365", concat($month, ":")), ",") - $day) * ( 1 - concat("0", substring-before(substring-after("...,2000:1,2004:1,2008:1,2012:1,2016:1,...", concat($year, ":")), ",")) * 1) + (366 - substring-before(substring-after( "1:00, 2:31, 3:60, 4:91, 5:121, 6:152, 7:182, 8:213, 9:244, 10:274, 11:305, 12:335, 13:366", concat($month, ":")), ",") - $day) * concat("0", substring-before(substring-after("...,2000:1,2004:1,2008:1,2012:1,2016:1,...", concat($year, ":")), ","))

Related

How to parse a calendar week number in Go [duplicate]

This question already has answers here:
Date range by week number Golang
(4 answers)
Closed 2 years ago.
How can I turn a string containing the year and an iso week date into a time object?
This is how the string I have looks like: 2020-15, where 2020 is the year and 15 is the iso week number. Ideally, I would like to get the first available timestamp of a week (Monday at midnight).
I read through the documentation of the Parse() method here https://golang.org/pkg/time/#Parse, but I cannot figure out how to come up with a layout string of the reference time where the week is taken into account.
You should be able to draw something up yourself pretty quickly by creating a new time.Time on January 1 of the specified year; advancing it to whatever day you want to treat as your canonical start of the week; then adding (7 * weekNumber) days to it, for example:
t := time.Date(year, 1, 1, 0, 0, 0, 0, location)
offset := (t.Weekday() + 7 - weekStart) % 7
t = t.Add(time.Duration(offset*24) * time.Hour)
t = t.Add(time.Duration((week-1)*7*24) * time.Hour)
Working example: https://play.golang.org/p/EjUpnRZRE6T

Delphi week number function based on system start of week

The DateUtils.WeekOfTheYear function is great but it uses the ISO 8601 standard definition of a week. That is, a week is considered to start on a Monday and end on a Sunday. I need a similar function that determines the week number based on the system setting for the start of the week. Or at least for either a sunday or monday start of week like MySQL's week function. Anyone have such a function?
ISO-8601 includes a great deal more than just the first day of the week in its specifications for these calculations. There are also rules which determine the first week in the year, for example.
It is not clear whether what you are looking for is a function to replicate the ISO-8601 calculation with these rules otherwise intact and solely varying the first day of the week, or a direct equivalent of the WEEK() function of MySQL, or something else only similar (and not fully defined).
Worth noting is that the MySQL WEEK() function accepts a parameter which does not determine an arbitrary day marking the start of the week, rather it indicates whether either of Sunday or Monday is to be used along with changing a number of other rules that determine the calculated result.
By contrast, the system setting for first day of the week on Windows itself can be ANY day of the week that the user wishes - Mon, Tue, Wed, Thu, Fri, Sat or Sun.
The implementation I provide below is a simple calculation (some might call it naive) which simply returns a value 0..53 based on the number of week periods, or part periods, elapsed between a date specified and the start of the year in which that date occurs.
The week in which 1st of Jan occurs for the year containing the specified date is deemed to be week 0.
Therefore if the 1st of Jan occurs on a Sunday and the "start of week" is defined as Monday then:
Sun, 01-Jan = Week 0
Mon, 02-Jan = Week 1
..
Sun, 08-Jan = Week 1
Mon, 09-Jan = Week 2
..
etc
The Implementation
I have split the implementation into two distinct parts.
The first (WeeksSince01Jan) accepts a date and a parameter indicating the day of week to be considered the first day of the week in the calculation.
This parameter takes a TSYSDayOfWeek value - an enum arranged such that the ordinal values for each day correspond to the values used in system locale settings for the days of the week. (The value returned by the RTL DayOfWeek function uses different values, defined in this code as TRTLDayOfWeek).
The second part of the implementation provides a LocaleWeeksSince01Jan, to demonstrate obtaining the locale defined first day of week for the current user. This is then simply passed thru to a call to WeeksSince01Jan.
type
TSYSDayOfWeek = (sdMon, sdTue, sdWed, sdThu, sdFri, sdSat, sdSun);
TRTLDayOfWeek = 1..7; // Sun -> Sat
function WeeksSince01Jan(const aDate: TDateTime;
const aFirstDayOfWeek: TSYSDayOfWeek): Word;
const
LOCALE_DOW : array[TRTLDayOfWeek] of TSYSDayOfWeek = (sdSun, sdMon, sdTue, sdWed, sdThu, sdFri, sdSat);
var
y, m, d: Word;
dayOfYearStart: TSYSDayOfWeek;
dtYearStart: TDateTime;
dtStartOfFirstWeekInYear: TDateTime;
iAdjust: Integer;
begin
// Get the date for the first day of the year and determine which
// day of the week (Mon-Fri) that was
DecodeDate(aDate, y, m, d);
dtYearStart := EncodeDate(y, 1, 1);
dayOfYearStart := LOCALE_DOW[DayOfWeek(dtYearStart)];
// Week calculation is simply the number of 7 day periods
// elapsed since the start of the year to the specified date,
// adjusted to reflect any 'offset' to the specified first day of week.
iAdjust := Ord(dayOfYearStart) - Ord(aFirstDayOfWeek);
result := (((Trunc(aDate) + iAdjust) - Trunc(dtYearStart)) div 7);
end;
function LocaleWeeksSince01Jan(const aDate: TDateTime): Word;
var
localeValue: array[0..1] of Char;
firstDayOfWeek: TSYSDayOfWeek;
begin
// Get the system defined first day of the week
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, localeValue, SizeOf(localeValue));
firstDayOfWeek := TSYSDayOfWeek(Ord(localeValue[0]) - Ord('0'));
result := WeeksSince01Jan(aDate, firstDayOfWeek);
end;
If you have more complex rules to determine the 0th or 1st week of a year based on numbers of days in that week etc, then you will need to modify this implementation accordingly. There is no attempt to accommodate such needs in the current implementation.
For Testing
The code below may be used as the basis for testing the output (using the system defined first day of the week):
const
YEAR = 2012;
var
d: Integer;
dt: TDateTime;
wk: Word;
begin
List.Items.Clear;
dt := EncodeDate(YEAR, 1, 1) - 7;
for d := 1 to 380 do
begin
dt := dt + 1;
wk := LocaleWeeksSince01Jan(dt);
List.Items.Add(Format('%s, %s = week %d', [ShortDayNames[DayOfWeek(dt)],
DateToStr(dt),
wk]));
end;
Where List is a reference to a TListbox.
Change the value of YEAR to produce a range of results that cover all dates in the specified year +/- an additional 7/8 days, to illustrate the change in result at year end of the preceding and succeeding years.
NOTE: 2012 is a year which demonstrates the possibility of returning dates in that year covering the full range of potential results, 0..53.
If you are only interested in week starting on Sunday instead on Monday you can simply substract 1 day from your DateTime value before feeding it to DateUtils.WeekOfTheYear function.
EDIT:
Response to David Heffernan comment:
Imagine what happens when you subtract 1 from January 1st
It depends on which day is on January 1st
From Embarcadero documentation: http://docwiki.embarcadero.com/Libraries/XE8/en/System.DateUtils.WeekOfTheYear
AYear returns the year in which the specified week occurs. Note that
this may not be the same as the year of AValue. This is because the
first week of a year is defined as the first week with four or more
days in that year. This means that, if the first calendar day of the
year is a Friday, Saturday, or Sunday, then for the first three, two,
or one days of the calendar year, WeekOfTheYear returns the last week
of the previous year. Similarly, if the last calendar day of the year
is a Monday, Tuesday, or Wednesday, then for the last one, two, or
three days of the calendar year, WeekOfTheYear returns 1 (the first
week of the next calendar year).
So if the week starts with Sunday instead of Monday then it means that week start and end days are simply shifted by one day backward.
So for such occasions it is best to use over-ridden version with additional variable parameter to which the year that this week belongs to is stored.
I've combined Deltics' great code with SilverWarior's simple idea to create a WeekOfYear function that handles the system week start day.
type
TSYSDayOfWeek = (sdMon, sdTue, sdWed, sdThu, sdFri, sdSat, sdSun);
function LocaleWeekOfTheYear(dte: TDateTime): word;
var
localeValue: array[0..1] of Char;
firstDayOfWeek: TSYSDayOfWeek;
yearOld,yearNew: word;
dteNew: TDateTime;
begin
// Get the system defined first day of the week
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, localeValue, SizeOf(localeValue));
firstDayOfWeek := TSYSDayOfWeek(Ord(localeValue[0]) - Ord('0'));
yearOld:= Year(dte);
if (firstDayOfWeek=sdSun) then
dteNew:= dte-1
else
dteNew:= dte+Ord(firstDayOfWeek);
yearNew:= Year(dteNew);
if (yearOld=yearNew) then
dte:= dteNew;
Result:= WeekOfTheYear(dte);
end;
To make the first day of the week is Saturday, I use to add 2 to the value of Now date.
As example WeekOf(Now + 2) : makes the first day is Saturday,
WeekOf(Now + 2) : makes the first day is Sunday,
WeekOf(Now + 0) : makes the first day is Monday,

Finding the day in which a given year begins

This question arose when I was trying to understand Sakamoto's algorithm for finding the day of a given date.
I found the working of the algorithm to be difficult to comprehend even after reading the following Stackoverflow answer
So, I decided to first solve a specific problem of finding the day in which a given year begins( Jan-1).
From the Sakamoto's algorithm, I just took the part of adding the additional days contributed by the leap and non-leap years.
My code is as follows:
public String getDay(String date)
{
String[] days = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
int day = Integer.parseInt(date.split("/")[0]);
int month = Integer.parseInt(date.split("/")[1]);
int year = Integer.parseInt(date.split("/")[2]);
year--; // to calculate the additional days till the previous year
int dayOfTheWeek = (year + year/4 - year/100 + year/400) % 7;
return days[dayOfTheWeek];
}
Thus, for the date "1/1/0001", it returns Sunday.
To verify its correctness, I implemented Sakamoto's algorithm and compared the results and my program's result always seems to be one day before the day returned by the Sakamoto's algorithm.
For the date "1/1/0001" my program returns Sunday, while Sakamoto's returns Monday.
So,
1) Does it mean that the Gregorian calendar started on Monday instead of Sunday??
2) If yes, does it mean I should add 1 to the result to get the right day or is my program logically incorrect?
Finally, I used TimeAndDate site's day calculator tool and "1/1/0001" starts on Saturday.
My final question is
3) On what day does the Gregorian calendar start?
Any light on the these questions is much appreciated.
Thanks,
What exactly is the point of reinventing the wheel?
Joda-Time is a de facto standard for date-time operations in Java, and it provides dayOfWeek method for its DateTime objects. See e.g. http://joda-time.sourceforge.net/userguide.html#Querying_DateTimes
If you are then still interested in details how to get the computation right, see https://github.com/JodaOrg/joda-time/blob/master/src/main/java/org/joda/time/chrono/BasicChronology.java#L538

In Ruby, how to compute the number of days until next Sunday? [duplicate]

This question already has answers here:
Rails Previous Sunday in Relation to Any DateTime
(2 answers)
Closed 9 years ago.
I'd like to find out how many days until next Sunday given some arbitrary date.
If the date supplied is Sunday, it should return 7.
I'm using the Date Class from the Ruby Standard Library.
require 'date'
today = Date.today
7-today.wday # Days until next Sunday
More generally, to answer this question for a general day d = 0,1,2,3,4,5,6 for Sun,Mon,Tue,Wed,Thu,Fri,Sat respectively:
DAYS_PER_WEEK = 7
(d-today.wday-1) % DAYS_PER_WEEK + 1

How to loop numerically + month and day over the past X years?

I need to loop through all of the days and months for the past couple decades numerically as well as to have the name of the month and day for each date. Obviously a few series of loops can accomplish this, but I wanted to know the most concise ruby-like way to accomplish this.
Essentially I'd need output like this for each day over the past X years:
3 January 2011 and 1/3/2011
What's the cleanest approach?
Dates can work as a range, so it's fairly easy to iterate over a range. The only real trick is how to output them as a formatted string, which can be found in the Date#strftime method, which is documented here.
from_date = Date.new(2011, 1, 1)
to_date = Date.new(2011, 1, 10)
(from_date..to_date).each { |d| puts d.strftime("%-d %B %Y and %-m/%-d/%Y") }
# => 1 January 2011 and 1/1/2011
# => 2 January 2011 and 1/2/2011
# => ...
# => 9 January 2011 and 1/9/2011
# => 10 January 2011 and 1/10/2011
(Note: I recall having some bad luck a ways back with unpadded percent formats like %-d in Windows, but if the above doesn't work and you want them unpadded in that environment you can remove the dash and employ your own workarounds.)
Given start_date & end_date:
(start_date..end_date).each do |date|
# do things with date
end
as David said, this is possible because of Date#succ. You can use Date#strftime to get the date in any format you'd like.
See if you can construct a Range where the min and max are Date objects, then call .each on the range. If the Date object supports the succ method this should work.

Resources