# Currency & Fiscal Handling

## Overview

Currency and fiscal context shape how a semantic query interprets monetary amounts and date grains, and how it formats results. Currency handling converts currency-typed measures from each record's source currency into a single target currency so that totals, calculated fields, and grouped results all report amounts in one consistent currency. Fiscal handling lets you group and filter dates by fiscal grains (fiscal year, quarter, month, week) rather than the calendar grains.

You set this context per query through the `semanticContext` object on the `structuredSemanticQuery`. `semanticContext` carries `currency`, `timezone`, and `locale`. The single most important thing to know about currency is precedence: a `currency` supplied in `semanticContext` overrides the model's default currency, which in turn overrides the org default. When no target currency resolves from any of these, currency-typed values are returned in their original record currency without conversion.

Currency conversion depends on a source-currency column that the model marks on each currency-bearing data object. That column, and the model's default currency, are defined in the Semantic Data Model; the target currency for a specific query is the only piece you set at query time.

## Metadata in the model

Two pieces of currency handling are defined in the model. First, each data object that holds currency amounts declares exactly one field whose `semanticDataType` is `RecordCurrency` — this is the column that stores the ISO currency code for each record and is the anchor for conversion. Second, the model can carry a default target currency in a nested `currency` object (`currency.id` = ISO code). Fiscal grouping and fiscal relative-date filters rely on date-typed fields defined on the model's data objects; there is no separate fiscal metadata to set per query.

For how these are defined, see [Semantic Data Object Field](/docs/data/semantic-layer/guide/connect-api-in-depth-entities.md#semantic-data-object-field-semanticdataobjectfield) for the `RecordCurrency` field and [Semantic Model](/docs/data/semantic-layer/guide/connect-api-in-depth-entities.md#semantic-model-semanticmodel) for the model default currency.

The time zone and locale in `semanticContext` are pure query-time knobs — no model metadata backs them.

## Query usage

### Set the target currency for a query

Set `semanticContext.currency.id` to an ISO currency code to convert every currency-typed field in the query into that currency. This value takes precedence over the model default and the org default. The query below selects a field from a logical view and requests results in euros; the response carries the resolved currency back in the enriched context.

```json
{
  "structured_semantic_query": {
    "fields": [
      {
        "expression": {
          "tableField": {
            "name": "SemanticAccount__dlm_semantic__Id__c",
            "tableName": "logicalTable"
          }
        },
        "alias": "name",
        "rowGrouping": true
      }
    ],
    "semantic_context": {
      "currency": {
        "id": "EUR"
      }
    }
  },
  "semantic_model": {
    "apiName": "Sales",
    "label": "Sales",
    "semanticLogicalViews": [
      {
        "apiName": "logicalTable",
        "semanticDataObjects": [
          {
            "apiName": "SemanticAccount__dlm",
            "dataObjectName": "ssot__Account__dlm",
            "dataObjectType": "Dmo",
            "semanticDimensions": [
              {
                "apiName": "SemanticAccount__dlm_semantic__Id__c",
                "dataType": "Currency",
                "dataObjectFieldName": "ssot__Id__c"
              },
              {
                "apiName": "SemanticAccount__dlm_semantic__account_source__c",
                "dataType": "Text",
                "semanticDataType": "RecordCurrency",
                "dataObjectFieldName": "ssot__AccountSource__c"
              }
              // ...
            ]
          }
          // ...
        ]
        // ...
      }
    ]
  }
}
```

> **Performance:** Currency conversion runs only when a currency field is part of the query, and each converted measure is wrapped in a per-row conversion. Omit currency fields you don't need to avoid the overhead.

### Convert currency in a calculated measure

Currency conversion also applies to currency-typed calculated measures. When no per-query `currency` is set, the model's default currency (the nested `currency` object on the model) is the target. In the query below the model default is `EUR`, and the calculated measure `currency_calc` — a `Currency`-typed expression over a currency measure — is converted to euros.

```json
{
  "structured_semantic_query": {
    "fields": [
      {
        "expression": {
          "semantic_field": {
            "name": "currency_calc"
          }
        },
        "row_grouping": true
      }
    ]
  },
  "semantic_model": {
    "currency": {
      "id": "EUR"
    },
    "apiName": "Sales",
    "label": "Sales",
    "semanticDataObjects": [
      {
        "apiName": "SemanticAccount__dlm",
        "dataObjectName": "ssot__Account__dlm",
        "dataObjectType": "Dmo",
        "semanticDimensions": [
          {
            "apiName": "test1",
            "dataType": "Text",
            "dataObjectFieldName": "ssot__Name__c",
            "semanticDataType": "RecordCurrency"
          }
          // ...
        ],
        "semanticMeasurements": [
          {
            "apiName": "Cost",
            "dataType": "Currency",
            "dataObjectFieldName": "ssot__Number__c"
          }
        ]
      }
    ],
    "semanticCalculatedMeasurements": [
      {
        "apiName": "currency_calc",
        "label": "currency_calc",
        "dataType": "Currency",
        "expression": "10 * [SemanticAccount__dlm].[Cost]"
      }
    ]
  }
}
```

### Group by fiscal dates

To group by a fiscal grain, reference a fiscal date function over a date field in a calculated expression and mark the field with `row_grouping`. The `FISCAL_YEAR` and `FISCAL_QUARTER` functions return the fiscal year and quarter of a date. This query groups by a computed fiscal quarter/year label and sets the time zone and locale in `semantic_context`.

```json
{
  "structured_semantic_query": {
    "fields": [
      {
        "expression": {
          "calculated_field": {
            "name": "fiscal_quarter_on_the_fly_calculation",
            "expression": "CONCAT('FY', TEXT(FISCAL_QUARTER(AccountSemanticLayer__dll.LastModifiedDate__c)), '-Q', TEXT(FISCAL_YEAR(AccountSemanticLayer__dll.LastModifiedDate__c)))"
          }
        },
        "row_grouping": true
      }
    ],
    "semantic_context": {
      "timezone": {
        "id": "Africa/Accra"
      },
      "locale": {
        "code": "be_BY"
      }
    }
  },
  "semanticModelApiName": "test_model"
}
```

### Filter by a relative fiscal date range

Relative date filters accept fiscal date parts as well as calendar parts. Use `relativeDateRange` inside a `BINARY_OPERATOR_BETWEEN` predicate and set `datePart` to a fiscal grain — `Fiscal_Week`, `Fiscal_Month`, `Fiscal_Quarter`, or `Fiscal_Year`. Combine it with `startOffset`, `endOffset`, and either `useCurrentDateAsEndDate` or an explicit `anchorDate` to define the window.

```json
{
  "structuredSemanticQuery": {
    "filter": {
      "binaryPredicate": {
        "leftExpression": {
          "tableField": {
            "name": "CreatedDate",
            "tableName": "SemanticAccount_SDO"
          }
        },
        "binaryOperator": "BINARY_OPERATOR_BETWEEN",
        "rightExpression": {
          "relativeDateRange": {
            "datePart": "Day",
            "useCurrentDateAsEndDate": true,
            "startOffset": -30,
            "endOffset": 1,
            "anchorDate": "2024-12-23T00:00:00.000"
          }
        }
      }
    },
    "fields": [
      // ...
    ]
  },
  "semanticModelId": "2SMxx0000004CAeGAM"
}
```

The supported `datePart` values are `Minute`, `Hour`, `Day`, `Week`, `Month`, `Quarter`, `Year`, `Fiscal_Week`, `Fiscal_Month`, `Fiscal_Quarter`, `Fiscal_Year`, and `Localized_Week`. Substitute one of the `Fiscal_*` values in the example above to filter on a fiscal window.

### Set the time zone and locale

Set `semanticContext.timezone.id` to shift datetime values and datetime-derived grains into a specific time zone, and `semanticContext.locale.code` to drive display formats for dates, numbers, and names. Both are set alongside `currency` in the same `semanticContext` object.

```json
{
  "structuredSemanticQuery": {
    "fields": [
      // ...
    ],
    "semanticContext": {
      "timezone": {"id": "America/Los_Angeles"},
      "locale": {"code": "en_US"}
    }
    // ...
  }
}
```

## Reference

| Field (wire name)               | Type          | Required | Description                                                                                                              |
| ------------------------------- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `semanticContext.currency`      | Currency      | N        | Target currency for the query. `currency.id` is an ISO currency code. Highest-precedence source for currency conversion. |
| `semanticContext.timezone`      | Timezone      | N        | Time zone applied to datetime values and datetime-derived grains. `timezone.id` is a time-zone identifier.               |
| `semanticContext.locale`        | Locale        | N        | Locale driving display formats for dates, numbers, and names. `locale.code` is a locale code.                            |
| `currency` (on `semanticModel`) | Currency      | N        | Model default target currency (`currency.id` = ISO code). Used when `semanticContext.currency` is absent.                |
| `relativeDateRange.datePart`    | String (enum) | N        | Date grain for a relative date filter; includes `Fiscal_Week`, `Fiscal_Month`, `Fiscal_Quarter`, `Fiscal_Year`.          |

For the full request schema, see [Request Reference](/docs/data/semantic-layer/guide/query-api-in-depth-fields.md).

## Limitations

- **Target currency resolves by precedence: `semanticContext.currency` → model default `currency` → org default.** If none resolves, currency-typed values are returned in their original record currency with no conversion.
- **Currency conversion requires a record-currency field.** Any data object whose currency fields are queried must declare a field with `semanticDataType: RecordCurrency`; otherwise the query fails.
- **Currency conversion does not apply to Calculated Insights Objects (CIO).** Currency fields on a CIO are returned in their stored currency.
- **You cannot filter by currency type**, and **as-of (dated) currency conversion is not supported** — conversion always uses current exchange rates.
- **Fiscal date parts are computed against the standard fiscal calendar.**

## Related

- [Filtering](/docs/data/semantic-layer/guide/query-api-in-depth-filtering.md) — Relative date filters, including fiscal `datePart` values.
- [Grouping](/docs/data/semantic-layer/guide/query-api-in-depth-grouping.md) — Grouping by dates and fiscal dates.
- [Calculated Fields](/docs/data/semantic-layer/guide/query-api-in-depth-calculated-fields.md) — Currency-typed calculated measures and fiscal date functions in expressions.
- [Semantic Data Object Field](/docs/data/semantic-layer/guide/connect-api-in-depth-entities.md#semantic-data-object-field-semanticdataobjectfield) — Authoring the `RecordCurrency` field.
- [Semantic Model](/docs/data/semantic-layer/guide/connect-api-in-depth-entities.md#semantic-model-semanticmodel) — Setting the model default currency.
- [Request Reference](/docs/data/semantic-layer/guide/query-api-in-depth-fields.md) — Complete field schema for `semanticContext`.
