如何将两日期间的在船工时按天分配(PowerBI M语言)
船员在船工时按实际日期拆分的M语言代码修改方案
问题核心
现有M语言代码将船员在船工时全部关联至月末日期,无法满足按实际日期统计工时的需求。需要调整代码,使工时按实际日期拆分:
- 起始日:统计从登船时间到当日结束的剩余时长
- 中间日:按24小时计算
- 结束日:统计从当日开始到下船时间的时长
关键修改点
原代码中生成日期列时,使用Date.EndOfMonth将所有日期转换为月末日期,只需移除该转换,直接使用原始的每日日期列表即可:
// 原错误代码 List.Transform ( LD, Date.EndOfMonth ) // 修改后代码 LD
修改后的完整M代码
let Kilde = Sql.Database("XXXXX", "YYYYYY"), CREW_CrewActivity = Kilde{[Schema="CREW",Item="CrewActivity"]}[Data], #"Fjernede kolonner" = Table.RemoveColumns(CREW_CrewActivity,{"LastModified", "X_CREATED", "X_CREATED_BY", "X_DEFAULT_TZ", "CompanyId", "LocationCompany", "LocationFlagState", "LocationImo", "LocationMainType", "LocationManager", "LocationMmsi", "LocationName", "LocationOwner", "LocationSegment", "LocationTypes", "Bunk", "Cabin", "Company", "CompanyName", "GangwayLog", "SignOffPlace", "SignOnPlace", "TagId", "FirstName", "LastName", "MiddleName", "Position", "Vessel"}), #"Filtrerte rader" = Table.SelectRows(#"Fjernede kolonner", each ([SignOff] <> null)), // 处理SignOff字段格式 #"Erstattet verdi SignOff" = Table.ReplaceValue(#"Filtrerte rader", "T", " ", Replacer.ReplaceText, {"SignOff"}), #"Uttrekte første tegn SignOff" = Table.TransformColumns(#"Erstattet verdi SignOff", {{"SignOff", each Text.Start(_, 16), type text}}), // 处理SignOn字段格式 #"Erstattet verdi SignOn" = Table.ReplaceValue(#"Uttrekte første tegn SignOff", "T", " ", Replacer.ReplaceText, {"SignOn"}), #"Uttrekte første tegn SignOn" = Table.TransformColumns(#"Erstattet verdi SignOn", {{"SignOn", each Text.Start(_, 16), type text}}), // 拆分日期与时间字段 #"Del kolonne med skilletegn" = Table.SplitColumn(#"Uttrekte første tegn SignOn", "SignOn", Splitter.SplitTextByEachDelimiter({" "}, QuoteStyle.Csv, false), {"SignOn.1", "SignOn.2"}), #"Del kolonne med skilletegn1" = Table.SplitColumn(#"Del kolonne med skilletegn", "SignOff", Splitter.SplitTextByEachDelimiter({" "}, QuoteStyle.Csv, false), {"SignOff.1", "SignOff.2"}), // 转换字段类型 #"Endret type" = Table.TransformColumnTypes(#"Del kolonne med skilletegn1",{{"SignOn.1", type date}, {"SignOn.2", type text}, {"SignOff.1", type date}, {"SignOff.2", type text}}), // 移除时间字段的冒号 #"Erstattet verdi" = Table.ReplaceValue(#"Endret type",":","",Replacer.ReplaceText,{"SignOn.2", "SignOff.2"}), // 重命名字段 #"Kolonner med nye navn" = Table.RenameColumns(#"Erstattet verdi",{{"SignOn.1", "Start Date"}, {"SignOn.2", "Start Time"}, {"SignOff.1", "Stop Date"}, {"SignOff.2", "Stop Time"}}), // 生成按日拆分的工时数据(核心修改部分) #"Egendefinert lagt til" = Table.AddColumn(#"Kolonner med nye navn", "Egendefinert", each [ SD = [Start Date], ST = Number.Round(Number.From([Start Time])/100,0), ED = [Stop Date], ET = Number.Round(Number.From([Stop Time])/100,0), LD = List.Dates( SD, Number.From ( ED-SD ) +1, Duration.From(1)), LT = if SD = ED then { ET - ST } else { 24-ST } & List.Repeat( { 24 }, List.Count( LD )-2 ) & { ET }, t = Table.FromColumns( { LD, // 核心修改:移除Date.EndOfMonth转换,直接使用实际日期列表 LT }, type table [ Date = Date.Type, Hrs = Int8.Type ] ) ][t] )[[Id],[CrewUNID],[Egendefinert]], // 移除错误行 #"Fjernede feil" = Table.RemoveRowsWithErrors(#"Egendefinert lagt til", {"Egendefinert"}), // 展开嵌套表 #"Utvidet Egendefinert" = Table.ExpandTableColumn(#"Fjernede feil", "Egendefinert", {"Date", "Hrs"}, {"Date", "Hrs"}) in #"Utvidet Egendefinert"
修改说明
- 核心调整:移除日期列表的
Date.EndOfMonth转换,直接使用List.Dates生成的实际每日日期,确保工时与对应日期正确关联 - 保留原有工时计算逻辑:
- 登船与下船为同一天时,直接计算时间差
- 跨天情况下,起始日统计剩余时长、中间日按24小时计算、结束日统计当日时长
- 其余数据清洗、格式转换步骤保持不变,确保原有数据处理流程的一致性
内容的提问来源于stack exchange,提问作者exxons
相关产品推荐
相关产品推荐

