Power BI Course
Data Formatting in Power Query
Formatting in Power Query is not about how numbers look on screen — it is about shaping values into the correct structure before they reach DAX and visuals. Rounding a number here changes the value stored in the model. Formatting a date here determines whether time intelligence functions work. Padding a text code here determines whether RELATED() finds a match. Every formatting decision in Power Query is a data decision, not a display decision.
Number Formatting and Rounding
Power Query stores numbers with full precision by default. Rounding in Power Query physically changes the stored value — a SUM of rounded values will differ from a rounded SUM. Understand this distinction before choosing where to round.
| M function | What it does | Example |
|---|---|---|
| Number.Round | Rounds to N decimal places using standard rounding (0.5 rounds up) | Number.Round(1234.567, 2) → 1234.57 |
| Number.RoundDown | Always rounds toward zero (floor). Never rounds up regardless of the decimal. | Number.RoundDown(1234.999, 0) → 1234 |
| Number.RoundUp | Always rounds away from zero (ceiling). Any non-zero decimal triggers rounding up. | Number.RoundUp(1234.001, 0) → 1235 |
| Number.Round (banker's) | Pass RoundingMode.ToEven as third argument. Rounds 0.5 to the nearest even number — reduces cumulative rounding bias in large datasets. | Number.Round(2.5, 0, RoundingMode.ToEven) → 2 |
| Number.IntegerDivide | Integer division — returns the whole-number quotient, discarding the remainder. Equivalent to floor(a/b). | Number.IntegerDivide(17, 5) → 3 |
| Number.Mod | Remainder after integer division. Used for bucketing — e.g. grouping order IDs into batches. | Number.Mod(17, 5) → 2 |
// Rounding applied in a Transform Column step
// Transform tab → Rounding → Round (or use Custom Column for full control)
// Round Revenue to 2 decimal places
#"Rounded Revenue" = Table.TransformColumns(
#"Changed Type",
{{"Revenue", each Number.Round(_, 2), type number}}
),
// Round Margin % to 1 decimal place
#"Rounded Margin" = Table.TransformColumns(
#"Rounded Revenue",
{{"MarginPct", each Number.Round(_, 1), type number}}
),
// Defensive rounding — wrap in try to handle null rows safely
#"Safe Round" = Table.TransformColumns(
#"Changed Type",
{{"Revenue", each try Number.Round(_, 2) otherwise null, type number}}
)
| OrderID | Revenue (raw) | Revenue (rounded 2dp) | MarginPct (rounded 1dp) |
|---|---|---|---|
| 1001 | 1234.5678 | 1234.57 | 32.4 |
| 1002 | 850.1249 | 850.12 | 18.7 |
| 1003 | 430.9999 | 431.00 | 9.1 |
| 1004 | null | null | null |
Date and Time Formatting
Date handling is the most consequential formatting task in Power Query. A column with type Date connects to a Calendar table through a relationship, enables time intelligence DAX functions, and displays correctly on axis scales. A column left as text does none of these things — it is just a string that happens to look like a date.
| M function | What it returns | Example input → output |
|---|---|---|
| Date.From | Converts a text or datetime value to a Date type | "2024-01-15" → #date(2024,1,15) |
| Date.FromText | Converts text to Date with an explicit format string — use when the source format is ambiguous (e.g. "01/02/24" could be Jan 2 or Feb 1) | Date.FromText("15/01/2024", [Format="dd/MM/yyyy"]) |
| Date.Year / Month / Day | Extracts the year, month number, or day number from a Date value | Date.Year(#date(2024,1,15)) → 2024 |
| Date.MonthName | Returns the full month name as text ("January", "February" …). Pass a culture for localisation. | Date.MonthName(#date(2024,3,1)) → "March" |
| Date.DayOfWeekName | Returns the day of week name ("Monday", "Tuesday" …). Day numbering starts Sunday=0 by default. | Date.DayOfWeekName(#date(2024,1,15)) → "Monday" |
| Date.ToText | Converts a Date to a formatted text string. Use for display labels — the result is text, not a date type. | Date.ToText(#date(2024,1,15), "MMM yyyy") → "Jan 2024" |
| Date.AddDays / AddMonths | Adds a number of days or months to a date. Useful for calculating due dates, grace periods, or projected dates. | Date.AddDays(#date(2024,1,15), 30) → #date(2024,2,14) |
// Common date formatting patterns in Custom Column
// Pattern 1 — Safe date parse from ambiguous text
// "01/02/2024" — is this Jan 2 or Feb 1? Specify the format explicitly.
= try Date.FromText([OrderDate], [Format="dd/MM/yyyy"]) otherwise null
// Pattern 2 — YearMonth sort key (text, sorts correctly)
= Text.From(Date.Year([OrderDate])) & "-"
& Text.PadStart(Text.From(Date.Month([OrderDate])), 2, "0")
// Result: "2024-01", "2024-02" ... "2024-12"
// Pattern 3 — Quarter label
= "Q" & Text.From(Date.QuarterOfYear([OrderDate]))
& " " & Text.From(Date.Year([OrderDate]))
// Result: "Q1 2024", "Q2 2024"
// Pattern 4 — Fiscal year (April start)
// Fiscal year starts April 1 — months Jan-Mar belong to previous FY
= if Date.Month([OrderDate]) >= 4
then "FY" & Text.From(Date.Year([OrderDate]))
else "FY" & Text.From(Date.Year([OrderDate]) - 1)
// Jan 2024 → "FY2023", Apr 2024 → "FY2024"
// Pattern 5 — Days since order (age of order)
= Duration.Days(DateTime.LocalNow() - Date.From([OrderDate]))
Text Padding and Formatting
Text padding ensures fixed-width codes and identifiers are consistent — critical when values are used as join keys between tables or exported to systems that expect a fixed-length field. The two padding functions work symmetrically: PadStart adds characters to the left, PadEnd adds them to the right.
// Text.PadStart(text, totalLength, padCharacter)
// Pads the LEFT side of the text until it reaches totalLength characters
// Pad a numeric ID to always be 6 digits
= Text.PadStart(Text.From([CustomerID]), 6, "0")
// 42 → "000042"
// 1234 → "001234"
// 100000 → "100000" (already 6 digits — no padding added)
// Text.PadEnd(text, totalLength, padCharacter)
// Pads the RIGHT side of the text until it reaches totalLength characters
// Pad a department code to always be 8 characters
= Text.PadEnd([DeptCode], 8, "-")
// "HR" → "HR------"
// "FINANCE" → "FINANCE-"
// "ENGINEER" → "ENGINEER" (already 8 — no padding)
// Combined — pad month number for YearMonth sort key
= Text.From(Date.Year([OrderDate])) & "-"
& Text.PadStart(Text.From(Date.Month([OrderDate])), 2, "0")
// Month 1 → "2024-01"
// Month 12 → "2024-12"
// Remove padding (strip leading zeros from a code)
= Text.TrimStart([ProductCode], "0")
// "000042" → "42"
// "001234" → "1234"
| CustomerID (raw) | PadStart 6 digits | DeptCode (raw) | PadEnd 8 chars |
|---|---|---|---|
| 42 | 000042 | HR | HR------ |
| 1234 | 001234 | FINANCE | FINANCE- |
| 100000 | 100000 | ENGINEER | ENGINEER |
Power Query Formatting vs DAX Formatting vs Visual Formatting
Three layers of formatting exist in a Power BI report, and applying a format at the wrong layer produces the wrong outcome. Understanding where each layer operates prevents common mistakes — especially the assumption that formatting a column in Power Query changes how it looks in a visual.
| Layer | What it controls | Changes the stored value? | Example |
|---|---|---|---|
| Power Query | The actual data value loaded into the model — type, precision, structure | Yes — rounding here changes the number stored | Number.Round([Revenue], 2) stores 1234.57 instead of 1234.5678 |
| DAX / Model | Column format strings in the model — how the value is displayed in all visuals by default, without changing the stored value | No — the stored value is unchanged | Setting format "#,##0.00" on Revenue column shows "$1,234.57" in all visuals but the model still stores 1234.5678 |
| Visual | Display format for a specific visual only — overrides the model format for that visual but changes nothing else | No — display only | Setting a card visual to show Revenue in thousands ("$1.2K") does not affect the table visual showing the full value |
Common Formatting Patterns — Quick Reference
// Number cleanup
= Number.Round([Revenue], 2) // 2 decimal places
= Number.Abs([Variance]) // remove negative sign
= Number.Sign([Profit]) // -1, 0, or 1
= Number.Sqrt([Area]) // square root
= Number.Power([Base], 2) // raise to power
// Text cleanup and formatting
= Text.Upper([Status]) // "SHIPPED"
= Text.Lower([Email]) // "alice@example.com"
= Text.Proper([CustomerName]) // "Alice Brown"
= Text.Trim([City]) // removes edge spaces
= Text.Clean([Description]) // removes control chars
= Text.Length([ProductCode]) // count characters
= Text.Reverse([Code]) // "ELEC" → "CELE"
= Text.Select([Phone], {"0".."9"}) // keep only digits
= Text.Remove([Phone], {"-", " ", "(", ")"}) // remove specific chars
// Date extraction
= Date.Year([OrderDate]) // 2024
= Date.Month([OrderDate]) // 3
= Date.Day([OrderDate]) // 15
= Date.QuarterOfYear([OrderDate]) // 1
= Date.WeekOfYear([OrderDate]) // 11
= Date.DayOfWeek([OrderDate]) // 0=Sun … 6=Sat
= Date.IsLeapYear(Date.Year([OrderDate])) // true / false
// Duration / age
= Duration.Days(DateTime.LocalNow() - [OrderDate]) // days since order
= Duration.TotalHours([ProcessingTime]) // hours as decimal
Teacher's Note: The single formatting mistake that causes the most downstream pain is leaving date columns as text. A text column that looks like "2024-01-15" will never connect to a Calendar table, will never work with DATEYTD or SAMEPERIODLASTYEAR, and will sort alphabetically rather than chronologically. Whenever you receive a date column, the very first thing you do is check its type icon in the column header — if it shows ABC it is text, and you fix it immediately with Changed Type or Date.FromText before doing anything else in the query.
Practice
Practice 1 of 3
You need to generate a YearMonth column like "2024-03" for sorting on a line chart axis. Single-digit months must be two digits. The M function that pads the left side of a text value with a character until it reaches a given length is Text.___.
Practice 2 of 3
A source file sends dates as "15/01/2024" — day first, then month. To parse this correctly without risk of day and month being swapped, you use Date.___ with an explicit format string specifying "dd/MM/yyyy".
Practice 3 of 3
Rounding Revenue to 2 decimal places in Power Query using Number.Round ___ the stored value in the model — it is not a display-only operation like setting a format string in column properties.
Lesson Quiz
Quiz 1 of 3
You round all Revenue values to 2 decimal places in Power Query. A finance colleague says the grand total is $0.02 off compared to summing the raw values in Excel. Why does this happen?
Quiz 2 of 3
A CustomerID column in the Orders table contains values like 42, 1234, and 100000 as numbers. The Customers table has the same IDs stored as zero-padded text: "000042", "001234", "100000". The relationship between the two tables fails to match any rows. What is the correct fix in Power Query?
Quiz 3 of 3
A date column in your report shows the correct values in the table visual but does not work with the SAMEPERIODLASTYEAR DAX time intelligence function, and the line chart axis shows dates in alphabetical rather than chronological order. What is the most likely cause?
Next up — Lesson 26 covers Custom Columns in depth, including the full M expression language for conditional logic, nested if statements, switch-style patterns, and building calculated columns that would be impossible to create through the point-and-click UI.