DataWeave 2.0 get time difference as a period - mule

I have DataWeave code that looks like below:
%dw 2.0
output application/java
var timezone = (now() >> "Pacific/Auckland") as String {format: "XXX"}
var t1 = '08:00:00.000' ++ timezone
var t2 = '21:00:00.000' ++ timezone
---
(|PT24H| - (t2-t1))
This results in a response in seconds as 39600 which is 11 hours. I want the response to be as |PT11H| rather than 39600. It works when we convert seconds to hours when dividing by 3600 to 11 hours but we need that to be like |PT11H| rather than 39600.
Above input t1 and t2 comes from config. we can't change the setup.

You can use seconds function of the dw::core::Periods module. It takes the number of seconds as Parameter and returns a Period.
%dw 2.0
import seconds from dw::core::Periods
output application/java
var timezone = (now() >> "Pacific/Auckland") as String {format: "XXX"}
var t1 = '08:00:00.000' ++ timezone
var t2 = '21:00:00.000' ++ timezone
---
seconds( |PT24H| - (t2 - t1) )
Another suggestion, since you are working on time periods and time differences the timezone does not really matter. You can reduce your code to below datawave
%dw 2.0
import seconds from dw::core::Periods
output application/java
var t1 = '08:00:00.000' as Time
var t2 = '21:00:00.000' as Time
---
seconds( |PT24H| - (t2 - t1) )

The 'seconds' function is introduced in DataWeave version 2.4 and Mule Runtime 4.4 under the periodic module
Reference: seconds | MuleSoft Documentation https://docs.mulesoft.com/dataweave/2.4/dw-periods-functions-seconds
so if your Mule Runtime Version is lower than 4.4 then you have to go for dividing by 3600 as mentioned in the question itself.
Below is that solution too for developers who are using Mule Runtime Version lower than 4.4
First:
%dw 2.0
output application/java
var timezone = (now() >> "Pacific/Auckland") as String {format: "XXX"}
var t1 = '08:00:00.000' ++ timezone
var t2 = '21:00:00.000' ++ timezone
---
"|PT" ++ (|PT24H| - (t2-t1))/3600 ++ "H|"
Explanation: Since (|PT24H| - (t2-t1)) gives '39600' as the result which is in seconds, now to convert seconds to minutes you need to divide by 60, and then to convert minutes to hours you need to again divide by 60, So instead you can directly divide by (60 * 60 i.e. 3600) and get the hours.
as per suggestion in a comment if time is not in exact hours then we can use the below DataWeave script
Second:
%dw 2.0
output application/java
var timezone = (now() >> "Pacific/Auckland") as String {format: "XXX"}
var t1 = '08:00:00.000' ++ timezone
var t2 = '21:00:00.000' ++ timezone
---
"PT$(|PT24H| - (t2-t1))S" as Period

Related

convert dateTime to salesforce required dateTime format in mule 4

For the dateTime "2022-11-29T19:12:21Z" getting INVALID_TYPE_ON_FIELD_IN_RECORD error from salesforce. So need to convert it in correct format that Salesforce accept.
Input: "2022-11-29T19:12:21Z"
Expected output: 2022-11-29T19:12:21.000+0000
I tried this script:
{
"lastDateTime": "2022-11-29T19:12:21Z" as DateTime {format: "yyyy-MM-dd'T'HH:mm:ss.SSS"}
}
Please help to get the expected output format.
A DateTime must have a timezone so you can not just parse the input string into it directly. The input also misses milliseconds so it can not be parsed with the milliseconds format .SSS.
You can convert to a LocalDateTime first, then add a timezone (+0:00), then format to string with milliseconds and timezone. A DateTime must have a timezone so you can not just parse the input
%dw 2.0
output application/json
---
{
"lastDateTime": ("2022-11-29T19:12:21Z" as LocalDateTime {format: "yyyy-MM-dd'T'HH:mm:ss'Z'"} ++ |+00:00|) as String {format: "yyyy-MM-dd'T'HH:mm:ss.SSSZ"}
}

Start week date based on week number and year

i'm trying to convert year and week number to Date, specifically i need to get first day of week by week number. My idea was to convert my String to Date and then gat firstdayofweek but im struggling with converting to Date with error:
Cannot coerce String (201601) to LocalDateTime, caused by: Text '201601' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {WeekOfWeekBasedYear[WeekFields[SUNDAY,1]]=1, Year=2016},ISO of type java.time.format.Parsed
My DW script:
%dw 2.0
output application/json
var date = '201601'
---
'Date' : date as LocalDateTime {format: "yyyyww"}
and also tried
%dw 2.0
output application/json
var date = '201601'
import * from dw::core::Periods
import * from dw::core::Dates
---
atBeginningOfWeek((atBeginningOfWeek(date[0 to 3]++ "-01-01")) as Date + days(date [4 to -1] * 7))
But they are not working good, any ideas?
I think your second solution is the answer to what you are trying to achieve.
%dw 2.0
output application/json
var date = '201601'
import * from dw::core::Periods
import * from dw::core::Dates
---
atBeginningOfWeek(((date[0 to 3]) ++ "-01-01") as Date) + days (date[4 to -1]*7)
I believe this is giving correct answer to your requirement.
The first script will not work because 1) using a LocalDateTime but there is no time in the input and 2) a year and a week don't make a date. DataWeave only has features to convert strings containing year, month and day into a date so even using w in the pattern will not work. Incidentally this could be the one case where the pattern YYYY (week based year) would probably apply if there was a way to use a year-week in DataWeave. Usually using uppercase Y in a date pattern in Java or DataWeave is a bug, because it is not the correct pattern for dates.
The second script seems correct, but we should try to avoid using string manipulation for dates. That's a bad pattern if there are library functions in the language used. It is not possible to avoid all because there is no way to convert a week to a date but we can at least avoid the concatenations. I prefer to implement the logic in a function to facilitate reuse.
%dw 2.0
output application/json
import * from dw::core::Dates
import * from dw::core::Periods
var yearWeekString = "201601"
fun beginningOfWeekYear(year: Number, week: Number)=
atBeginningOfWeek(atBeginningOfWeek(date({ year: year, month: 1, day: 1})) + days(week * 7 ))
---
{
"201601": beginningOfWeekYear(yearWeekString[0 to 3] as Number, yearWeekString[4 to -1] as Number),
"202041": beginningOfWeekYear(2020, 41)
}
Output:
{
"201601": "2015-12-27",
"202041": "2020-10-04"
}
I validated the output using a week calendar.

Date to DateTime conversion in DataWeave 2

Input date is coming in this format "2022-04-30" and I want to convert it to date time and time should be zeros like 2022-05-15T00:00:00Z.
How it can be achieved using DataWeave 2.0?
Convert the input string to a Date, then add the time to create a DateTime output. Then just convert to String. The default pattern seem to be adequate that you need.
%dw 2.0
output application/json
var sourceDate="2022-04-30"
---
(sourceDate as Date {format: "yyyy-MM-dd"} ++ |00:00:00Z|) as String
Output:
"2022-04-30T00:00:00Z"
If you want the result as String you can just Append "T00:00:00Z" to your date string
%dw 2.0
output application/json
var sourceDate="2022-04-30"
---
sourceDate ++ "T00:00:00Z"
And if you want a DateTime Object you can just coerce it to DateTime using as keyword. It will work as your date string is already in the required format.
%dw 2.0
output application/json
var sourceDate="2022-04-30"
---
(sourceDate ++ "T00:00:00Z") as DateTime

how to format month/day for 2 digits in mule4?

Im trying to create my filename in s3 with month/date format.
I dont want May to be printed as 5. It has to be '05'
I tried
now().month as Number {format: "00"}
and
now().month as Number {format: "##"}
Both prints 5. not as 05.
<set-variable value="#[now().year ++ '/' ++ now().month as Number {format: "00"}++ '/'++ now().day as Number {format: "##"} ++'/'++ now() as String {format: "yyyyMMdd_HHmmss"} ++".json"]" doc:name="S3-filename" doc:id="ff101e31-4f6c-45f5-9669-a60fbc32204e" variableName="s3filename"/>
Dont's do multiple transformations to date, to number, to string. Transform directly to string. Pay attention that Month is MM (upper case) and minutes are mm (lower case)
https://simpleflatservice.com/mule4/Date_format.html
%dw 2.0
output application/java
---
now() as String {format: "MM"}

Pig Get Hour and Minute of Epoch Timestamp in Milliseconds

I have a column of bytearray epoch timestamps in milliseconds in pig. I was wondering how to get the hour and minute cooresponding to this timestamp.
For example:
Hour(1441016271778) = 10
Minute(1441016271778) = 17
GetHour and GetMinute from the pig docs isn't working, it produces null.
GetHour and GetMinute will take DateTime object as input.
Ref :
http://pig.apache.org/docs/r0.12.0/func.html#get-hour
http://pig.apache.org/docs/r0.12.0/func.html#get-minute
Input :
1441016271778
Pig Script :
A = LOAD 'input.csv' USING PigStorage(',') AS (epoch_time:long);
B = FOREACH A GENERATE GetHour(ToDate(epoch_time)) AS hour, GetMinute(ToDate(epoch_time)) AS min;
Output :
(3,17)