Add Months or Years to milliseconds in JSONata - jsonata

I want to add several months or years to a given date in milliseconds in JSONata, so that it can do something like today plus three months. I didn't find any function to do that job in JSONata, so I implemented a function on my own. I calculated one month in milliseconds and multiply it with the amount of months I want to add. The following code shows the function in action.
(
$addMonths := function($time, $months) {
2628000000 * $months + $time
};
{
"datePlus3Month": $addMonths($millis(), 3)
}
)
This seems to work, but I don't know how accurate it is, because every month hasn't the same amount of days. So is there a better solution to achieve a more accurate result?

I just had the same problem. My solution seems rather clunky to me, but it works. Most likely there is a much easier way.
$addMonths := function($dateString, $addMonths) {(
$date := $dateString ~> $toMillis();
$newYear := ($date ~> $fromMillis("[Y,4]") ~> $number());
$newMonth := ($date ~> $fromMillis("[M]") ~> $number()) + $addMonths;
$newDay := ($date ~> $fromMillis("[D]") ~> $number());
$newMonth > 12
? $newYear := $newYear + 1;
$newMonth > 12
? $newMonth := $newMonth - 12;
$lastDay := (
$newMonth in [1,3,5,7,8,10,12]
? 31
: $newMonth in [4,6,9,11]
? 30
: ( $newYear%4=0
and
($newYear%100 != 0 or $newYear%400 = 0)
? 29
: 28)
);
$newDay > $lastDay
? $newDay := $lastDay;
( $newYear
& "-"
& $newMonth
& "-"
& $newDay
) ~> $toMillis("[Y]-[M]-[D]")
~> $fromMillis()
)};

You could try to transform into milliseconds, add what you need and then transform back.
$fromMillis($toMillis("2023-02-02") + 6.307e+10);
This results in: "2025-01-31T23:26:40.000Z"

Related

How to validate the timezone

I need to validate the timezone value that I have been given and that too i want to parse it in a particular date format and time zone should be "-1300 to 1400" (+/-HHMM).
I have tried with some, but I'm not able to get validate the time zone.
If timezone = "-1260"(it's a invalid value) , then it should print "Invalid time zone" but its not behaving like that.
Here's the code I've tried - https://play.golang.org/p/kbTsQAW-f-_r
var validTZ = regexp.MustCompile(`[+-][0-9]{4}$`)
tz:= "-1260"
tzInt, _ := strconv.Atoi(tz)
t1 := time.Now().UTC()
formattedDate := t1.Format("2006-01-02T15:04:05.000")
formattedDate += tz
_,err:=time.Parse("2006-01-02T15:04:05.000-0700",formattedDate)
if !validTZ.MatchString(tz) || (tzInt >= -1300 && tzInt <= 1400) || err != nil {
fmt.Println("Invalid time zone")
}
It is true that tz (1260) is tzInt >= -1300 && tzInt <= 1400
But your code is:
!(tzInt >= -1300 && tzInt <= 1400)
The ! negates the condition, making it tzInt < -1300 || tzInt > 1400: that is why "Invalid time zone" is not displayed.
As commented by the OP, you can also print that error based on a more precise regex:
^[+-]([0-9]{2})([0-5]{1})([0-9]{1})$
That will prevent any xx6y value.

Get 12 hour from time in Go

Go noob here, and all I want to do is use the time format constants list https://golang.org/src/time/format.go that are mentioned in 3 posts here on SO (https://stackoverflow.com/a/20234207 https://stackoverflow.com/a/14106561 https://stackoverflow.com/a/20234207). None of which including the docs (at least that I can tell) have an example of how to use them.
I would expect this to work (but it clearly does not):
t := time.Now()
log.Println(t.stdHour12())
Can you please tell me how to get only the hour (in 12 hour time) for a given time t (ex: 10 from 2021-03-09 22:45:04.009063861 -0500 EST)?
const (
stdLongMonth = "January"
stdMonth = "Jan"
stdNumMonth = "1"
stdZeroMonth = "01"
stdLongWeekDay = "Monday"
stdWeekDay = "Mon"
stdDay = "2"
stdUnderDay = "_2"
stdZeroDay = "02"
stdHour = "15"
stdHour12 = "3"
stdZeroHour12 = "03"
stdMinute = "4"
stdZeroMinute = "04"
stdSecond = "5"
stdZeroSecond = "05"
stdLongYear = "2006"
stdYear = "06"
stdPM = "PM"
stdpm = "pm"
stdTZ = "MST"
stdISO8601TZ = "Z0700" // prints Z for UTC
stdISO8601ColonTZ = "Z07:00" // prints Z for UTC
stdNumTZ = "-0700" // always numeric
stdNumShortTZ = "-07" // always numeric
stdNumColonTZ = "-07:00" // always numeric
)
Thanks in advance!
EDIT: From the answers received so far, I see that I cannot use the constants above to achieve what I want so I changed the wording of this question to specifically ask to return the hour (and just the hour) for a given time.
The Time object specifies the full date and time. You can extract just the time, if you like:
func main() {
t := time.Now()
fmt.Println(t.Format(time.Kitchen))
}
time.Kitchen is defined in the time package as Kitchen = "3:04PM"
If you want to understand how the format is interpreted, read this piece of documentation carefully
If you just need the hour, call the Hour() method on a Time object. If you want it in 12-hour format, you can just do modulo 12:
func main() {
t := time.Now()
fmt.Println(t.Hour())
fmt.Println(t.Hour() % 12)
}
These are constants representing tokens used internally by formatting code in time package (note they start with lower letter so they aren't exported and you can't even use them outside time package).
If you want to come up with your own format in Go (for both parsing and output) you simply define it using these tokens "as example" and Format() will parse it and apply that format (if valid) to itself.
const (
MyLayout = "3"
)
func main() {
t := time.Now()
fmt.Println(t.Format(MyLayout))
}
Available tokens are listed for example here.

ffmpeg-python trim why not concat

I want to split the video, do some logical processing, and finally merge it
import ffmpeg
info = ffmpeg.probe("test.mp4")
vs = next(c for c in info['streams'] if c['codec_type'] == 'video')
num_frames = vs['nb_frames']
arr = []
in_file = ffmpeg.input('test.mp4')
for i in range(int(int(num_frames) / 30) + 1):
startTime = i * 30 + 1
endTime = (1 + i) * 30
if endTime >= int(num_frames):
endTime = int(num_frames)
# more more
arr.append(in_file.trim(start_frame=startTime, end_frame=endTime))
(
ffmpeg
.concat(arr)
.output('out.mp4')
.run()
)
I don't understand why this is happening
TypeError: Expected incoming stream(s) to be of one of the following types: ffmpeg.nodes.FilterableStream; got <class 'list'>
Perhaps this is a little too late but you could try
.concat(*arr)
This worked for me with a list of defined start- and endframes

Calculating Total Job Experience

I need to calculate the total job experience as year value. Users add experiences with starting and ending dates to their resumes, just like Linkedin. But there is no any certain pattern. For instance;
A user may have a resume like that;
Experience 2
08.2012 - 01.2015
Experience 1
01.2011 - 01.2013
The user started their second experience while the first hasn't finished yet. So resumes may have many overlapping experiences. Overlapping also may occur between more than 2. So I need to consider many cases.
I tried to visualise the experience and year relationship for you.
I just need to develop an algorithm covering all the cases for this issue.
Sort by start date
start at the beginning and accumulate overlapping experiences (i.e. treat as one)
e.g. (Jan 2012, Jan 2015), (Jan 2014, Dec 2016) overlap, so we treat it as a single experience
This "super experience" begins at the start of the first, and ends at the end of the last; (Jan 2012, Dec 2016)
This is assuming that there can be gaps in experience, so we don't want to treat the entire history as one long "super experience"
I just did this
Sort the experiences by Begin Date.
Use 2 variables, that represent the begin of work and the end called Begin
and End.
If end and begin are empty it means that is the first date, we filled with the first experience, and we calculate the month count between the begin and end of this experience and and then this months count add to our months accumulator.
if the end and begin date of next experience is not between our begin and end variables, we calculate the months count from the experience and then add it to our accumulator.
If the begin date of next experience is between our begin and end variables, we calculate the months count between our end date as begin and the experience end date as end, and then that difference add to our months accumulator.
as you can see every time we set our new end if the experience end is greater than ours.
at the end we get the months, if you divide by 12 you get the years exactly you can round it if you want
NOTE: I Mapped the experiences, if not have End it means that is equivalent to NOW
you can see all the code below
function monthDiff(d1, d2) {
var m = (d1.getFullYear() - d2.getFullYear()) * 12 +
(d1.getMonth() - d2.getMonth());
if (d1.getDate() < d2.getDate()) --m;
return m;
}
function dateCheck(from, to, check) {
var fDate, lDate, cDate;
fDate = Date.parse(from);
lDate = Date.parse(to);
cDate = Date.parse(check);
if (cDate <= lDate && cDate >= fDate) {
return true;
}
return false;
}
function calculateYearsOfExperience(experiences) {
if (!experiences) return 0;
let months = 0;
let now = new Date();
let sorted = experiences
.sort((a, b) => {
return new Date(a.begin) - new Date(b.begin);
})
.map(experience => {
if (!experience.end) experience.end = now;
return { begin: experience.begin, end: experience.end };
});
let begin;
let end;
for (var i in sorted) {
let dif = 0;
if (!end && !begin) {
dif = monthDiff(sorted[i].begin, sorted[i].end);
begin = sorted[i].begin;
end = sorted[i].end;
} else if (
!dateCheck(begin, end, sorted[i].begin) &&
!dateCheck(begin, end, sorted[i].end)
) {
dif = monthDiff(sorted[i].begin, sorted[i].end);
end = sorted[i].end;
} else if (dateCheck(begin, end, sorted[i].begin)) {
dif = monthDiff(end, sorted[i].end);
end = sorted[i].end;
}
months += dif;
}
return months / 12;
}
experiences = [
# (start date, end date),
(date(2012, 8, 1), date(2015, 1, 30)),
(date(2011, 1, 1), date(2013, 1, 30))
]
print(sum((end_date - start_date).days/365 for start_date, end_date in experiences))
Create an array full of 0. Element range: Start would be the very first hire date, last would be current date / last working date. For every year you have 12 elements that can be 0/1. After filling in the array count the elements that have the value 1. If you need to take into account the overlapping then ignore the 0/1 part and give +1 for every month worked.
This is c# code, but you'll get the steps in algorithm. It returns total number of months which you can convert into year and month format.
var sortedList = expList
.OrderBy(a => a.start_year)
.ThenBy(a => a.start_month)
.ThenBy(a => a.end_year)
.ThenBy(a => a.end_month)
.ToList();
int totalMonths = 0;
int totalDays = 0;
DateTime? prevEndDate = null;
foreach (var exp in sortedList)
{
if(exp.start_month != null && exp.start_year != null)
{
var startDate = new DateTime((int)exp.start_year, (int)exp.start_month, 1);
var endDate = (bool)exp.is_present ?
DateTime.Now :
new DateTime((int)exp.end_year, (int)exp.end_month, 1);
if (prevEndDate != null && prevEndDate > startDate)
{
startDate = (DateTime)prevEndDate;
}
var timespan = endDate.Subtract(startDate);
var tempdate = DateTime.MinValue + timespan;
totalMonths = totalMonths + (tempdate.Year - 1) * 12 + tempdate.Month - 1;
totalDays = totalDays + tempdate.Day - 1;
prevEndDate = endDate;
}
}
if (totalDays > 0)
{
totalMonths = totalMonths + 1;
}
public static function YearCalculation($id=null) {
if($id=="")
$employee_id=#Auth::guard('web_employee')->user()->id;
else
$employee_id=$id;
$employee_exp = Experience::where('employee_id',$employee_id)->orderBy("experience_from","ASC")->get();
//print_r($employee_exp ); exit;
$years = 0;
$months = 0;
$days = 0;
$sum=0;
$lastfromdate=0;
$last_endDate=0;
if(#$employee_exp!=null){
foreach(#$employee_exp as $experience){
$fdate = #$experience->experience_from;
if($experience->is_current==0){
$tdate = #$experience->experience_to;
}else{
$tdate = date("Y-m-d");
}
if($last_endDate != date("Y-m-d") ){
if( $fdate < $last_endDate ){
$start_date1 = strtotime($last_endDate);
$end_date1 = strtotime($tdate);
$interval1 = ($end_date1 - $start_date1)/60/60/24;
$sum +=$interval1;
}
else{
$start_date2 = strtotime($fdate);
$end_date2 = strtotime($tdate);
$interval2 = ($end_date2 - $start_date2)/60/60/24;
$sum +=$interval2;
}
if($last_endDate < $tdate){
$last_endDate=$tdate;
}
}
}
$years = ($sum / 365) ;
$years = floor($years);
$month = ($sum % 365) / 30.4166;
$month = floor($month);
$days = ($sum % 365) % 30.4166;
//$total=date_diff(0,$tmstamp);
//$total_year=$years.' years, ' .$month.' months and '.$days.($days==1?' day':' days');
$total_year=($years==0?'':($years==1?$years.' year':$years.' years and ')) .($month==0?'':($month==1?$month.($days>1?'+':'').' month':$month.($days>1?'+':'').' months'));
return $total_year;
}
}

YouMax video upload date

I've been using the YouMax plugin which enables you to embed your YouTube channel on your website. However, I am having problems as it displays the uploaded date in months and years. I'd like it to display days, weeks, months and years.
You can view the source code here http://jsfiddle.net/wCKKU/
I believe that its this that needs adjusting to make it calculate in day, weeks, months and years.
function getDateDiff(timestamp) {
if (null == timestamp || timestamp == "" || timestamp == "undefined") return "?";
var splitDate = ((timestamp.toString().split('T'))[0]).split('-');
var d1 = new Date();
var d1Y = d1.getFullYear();
var d2Y = parseInt(splitDate[0], 10);
var d1M = d1.getMonth();
var d2M = parseInt(splitDate[1], 10);
var diffInMonths = (d1M + 12 * d1Y) - (d2M + 12 * d2Y);
if (diffInMonths <= 1) return "1 month";
else if (diffInMonths < 12) return diffInMonths + " months";
var diffInYears = Math.floor(diffInMonths / 12);
if (diffInYears <= 1) return "1 year";
else if (diffInYears < 12) return diffInYears + " years"
}
You could modify the plugin by a small block of code in the middle of the function:
var d2M = parseInt(splitDate[1], 10); // this line is already there
var d1D = d1.getDate();
var d2D = parseInt(splitDate[2],10);
var diffInDays = (d1D + 30 *d1M + 12 * d1Y) - (d2D + 30 *d2M + 12 *d2Y);
if (diffInDays < 2) return "1 day";
else if (diffInDays < 7) return diffInDays+" days";
else if (diffInDays > 7 && diffInDays < 14) return "1 week";
else if (diffInDays > 14 && diffInDays < 30) return Math.floor(diffInDays / 7) + " weeks";
var diffInMonths = (d1M + 12 * d1Y) - (d2M + 12 * d2Y); // this line is already there
Note that this isn't a particularly elegant way to handle the issue, but it matches the coding style the plugin is already using, and at least won't break anything else.
Also, as a side comment, if you're modifying the plugin code you'll want to fix a bug in it at the same time. Getting the current month should look like this:
var d1M = d1.getMonth() + 1;
This is because in Javascript, the getMonth() function returns the month on a zero-based index, and your math won't be reliable unless you switch it to a one-based index.

Resources