Repository: obsidian-tasks-group/obsidian-tasks
Pull request #1723 (2023-03-05 09:08:34)

feat: add created date to task
* Add field createdDate to task
* Add option (false by default) to add created on every new task.
* Update tests

It will be practical to query old tasks using dataview or maybe later add ability to obsidian-tasks Query.

<!--- Provide a general summary of your changes in the Title above -->

# Description

<!--- Describe your changes in detail -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

Query old tasks, based on field shorthands in dataview: https://blacksmithgu.github.io/obsidian-dataview/annotation/metadata-tasks/#field-shorthands

<!--- If it fixes an open issue, please link to the issue here. -->

## How has this been tested?

<!--- Please describe in detail how you tested your changes. -->

Place new main.js to my vault, and try to edit and add tasks. On newly added, created field apperae

<!--- Include details of your testing environment, tests ran to see how -->
<!--- your change affects other areas of the code, etc. -->

## Screenshots (if appropriate)

![image](https://user-images.githubusercontent.com/2872741/222951738-5336f5f2-b79d-4b62-9063-9f194f27a222.png)


## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

Changes visible to users:

- [ ] **Bug fix** (prefix: `fix` - non-breaking change which fixes an issue)
- [x] **New feature** (prefix: `feat` - non-breaking change which adds functionality)
- [ ] **Breaking change** (prefix: `feat!!` or `fix!!` - fix or feature that would cause existing functionality to not work as expected)
- [ ] **Documentation** (prefix: `docs` - improvements to any documentation content)
- [ ] **Sample vault** (prefix: `vault` - improvements to the [Tasks-Demo sample vault](https://github.com/obsidian-tasks-group/obsidian-tasks/tree/main/resources/sample_vaults/Tasks-Demo))

Internal changes:

- [ ] **Refactor** (prefix: `refactor` - non-breaking change which only improves the design or structure of existing code, and making no changes to its external behaviour)
- [x] **Tests** (prefix: `test` - additions and improvements to unit tests and the smoke tests)
- [ ] **Infrastructure** (prefix: `chore` - examples include GitHub Actions, issue templates)

## Checklist

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [x] My code follows the code style of this project and passes `yarn run lint`.
- [x] My change requires a change to the documentation.
- [ ] I have [updated the documentation](https://publish.obsidian.md/tasks-contributing/Documentation/About+Documentation) accordingly.
- [ ] My change has adequate [Unit Test coverage](https://publish.obsidian.md/tasks-contributing/Testing/About+Testing).

## Terms

<!--
By submitting this pull request, you must agree to follow our
[contributing guide](https://publish.obsidian.md/tasks-contributing) and
[Code of Conduct](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/CODE_OF_CONDUCT.md).
Put an x in the boxes to confirm you agree.
-->

- [ ] My contribution follow this project's [contributing guide](https://publish.obsidian.md/tasks-contributing)
- [x] I agree to follow this project's [Code of Conduct](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/CODE_OF_CONDUCT.md)



Patch:
diff --git a/docs/getting-started/dates.md b/docs/getting-started/dates.md
index f774fd9b..ca162c63 100644
--- a/docs/getting-started/dates.md
+++ b/docs/getting-started/dates.md
@@ -92,6 +92,19 @@ starts before tomorrow
 ```
 ````
 
+## ➕ Created
+
+It can happen that you want to log, when task was created.
+Obsidian tasks can automatically add created date for tasks created via 'Create or edit task', when settings 'Set created date on every added task' is enabled.
+
+Created dates use a heavy plus emoji.
+
+```markdown
+- [ ] take out the trash ➕ 2021-04-09
+```
+
+Filtering currently is not implemented for created field.
+
 ## Finding mistakes in dates
 
 Tasks does not automatically report any problem tasks that have invalid dates, such as on the 32nd day of a month. These task will silently not be found by date-based searches.
diff --git a/docs/queries/layout.md b/docs/queries/layout.md
index a8981850..f0750c11 100644
--- a/docs/queries/layout.md
+++ b/docs/queries/layout.md
@@ -28,6 +28,7 @@ The following elements exist:
 - `backlink`
 - `urgency`
 - `priority`
+- `created date`
 - `start date`
 - `scheduled date`
 - `due date`
diff --git a/docs/quick-reference/index.md b/docs/quick-reference/index.md
index 544d7a8e..ff820872 100644
--- a/docs/quick-reference/index.md
+++ b/docs/quick-reference/index.md
@@ -21,6 +21,7 @@ This table summarizes the filters and other options available inside a `tasks` b
 | `done (before, after, on) <date>`<br>`has done date`<br>`no  done date`<br>`done date is invalid`                                                                                                   | `sort by done`                              | `group by done`        | `hide done date`       |
 | `status.name (includes, does not include) <string>`<br>`status.name (regex matches, regex does not match) /regex/i`                                                                                 | `sort by status.name`                       | `group by status.name` |                        |
 | `status.type (is, is not) (TODO, DONE, IN_PROGRESS, CANCELLED, NON_TASK)`                                                                                                                           | `sort by status.type`                       | `group by status.type` |                        |
+|                                                                                                                                                                                                     |                                             |                        | `hide created date`    |
 | `starts (before, after, on) <date>`<br>`has start date`<br>`no  start date`<br>`start date is invalid`                                                                                              | `sort by start`                             | `group by start`       | `hide start date`      |
 | `scheduled (before, after, on) <date>`<br>`has scheduled date`<br>`no  scheduled date`<br>`scheduled date is invalid`                                                                               | `sort by scheduled`                         | `group by scheduled`   | `hide scheduled date`  |
 | `due (before, after, on) <date>`<br>`has due date`<br>`no  due date`<br>`due date is invalid`                                                                                                       | `sort by due`                               | `group by due`         | `hide due date`        |
diff --git a/src/Commands/CreateOrEditTaskParser.ts b/src/Commands/CreateOrEditTaskParser.ts
index e15bf12f..d97ed8a8 100644
--- a/src/Commands/CreateOrEditTaskParser.ts
+++ b/src/Commands/CreateOrEditTaskParser.ts
@@ -3,6 +3,7 @@ import { Priority, Task, TaskRegularExpressions } from '../Task';
 import { DateFallback } from '../DateFallback';
 import { StatusRegistry } from '../StatusRegistry';
 import { TaskLocation } from '../TaskLocation';
+import { getSettings } from '../Config/Settings';
 
 /**
  * Read any markdown line and treat it as a task, for the purposes of
@@ -30,12 +31,19 @@ export const taskFromLine = ({ line, path }: { line: string; path: string }): Ta
         return task;
     }
 
+    const { setCreatedDate } = getSettings();
+    let createdDate: moment.Moment | null = null;
+    if (setCreatedDate) {
+        createdDate = window.moment();
+    }
+
     // If we are not on a line of a task, we take what we have.
     // The non-task line can still be a checklist, for example if it is lacking the global filter.
     const nonTaskMatch = line.match(TaskRegularExpressions.nonTaskRegex);
     if (nonTaskMatch === null) {
         // Should never happen; everything in the regex is optional.
         console.error('Tasks: Cannot create task on line:', line);
+
         return new Task({
             status: Status.TODO,
             description: '',
@@ -44,6 +52,7 @@ export const taskFromLine = ({ line, path }: { line: string; path: string }): Ta
             indentation: '',
             listMarker: '-',
             priority: Priority.None,
+            createdDate,
             startDate: null,
             scheduledDate: null,
             dueDate: null,
@@ -79,6 +88,7 @@ export const taskFromLine = ({ line, path }: { line: string; path: string }): Ta
         listMarker,
         blockLink,
         priority: Priority.None,
+        createdDate,
         startDate: null,
         scheduledDate: null,
         dueDate: null,
diff --git a/src/Config/Settings.ts b/src/Config/Settings.ts
index 2fa8c624..b38f7f3e 100644
--- a/src/Config/Settings.ts
+++ b/src/Config/Settings.ts
@@ -16,6 +16,7 @@ export type HeadingState = {
 export interface Settings {
     globalFilter: string;
     removeGlobalFilter: boolean;
+    setCreatedDate: boolean;
     setDoneDate: boolean;
     autoSuggestInEditor: boolean;
     autoSuggestMinMatch: number;
@@ -42,6 +43,7 @@ export interface Settings {
 const defaultSettings: Settings = {
     globalFilter: '',
     removeGlobalFilter: false,
+    setCreatedDate: false,
     setDoneDate: true,
     autoSuggestInEditor: true,
     autoSuggestMinMatch: 0,
diff --git a/src/Config/SettingsTab.ts b/src/Config/SettingsTab.ts
index 1d57a1bb..4b191e5d 100644
--- a/src/Config/SettingsTab.ts
+++ b/src/Config/SettingsTab.ts
@@ -114,6 +114,19 @@ export class SettingsTab extends PluginSettingTab {
         containerEl.createEl('h4', { text: 'Date Settings' });
         // ---------------------------------------------------------------------------
 
+        new Setting(containerEl)
+            .setName('Set created date on every added task')
+            .setDesc(
+                "Enabling this will add a timestamp ➕ YYYY-MM-DD before other date values in a task is created with 'Create or edit task'",
+            )
+            .addToggle((toggle) => {
+                const settings = getSettings();
+                toggle.setValue(settings.setCreatedDate).onChange(async (value) => {
+                    updateSettings({ setCreatedDate: value });
+                    await this.plugin.saveSettings();
+                });
+            });
+
         new Setting(containerEl)
             .setName('Set done date on every completed task')
             .setDesc('Enabling this will add a timestamp ✅ YYYY-MM-DD at the end when a task is toggled to done')
diff --git a/src/Query/Query.ts b/src/Query/Query.ts
index 2c758d54..10e0c17d 100644
--- a/src/Query/Query.ts
+++ b/src/Query/Query.ts
@@ -25,7 +25,7 @@ export class Query implements IQuery {
         /^group by (backlink|done|due|filename|folder|happens|heading|path|priority|recurrence|recurring|root|scheduled|start|status|tags)/;
 
     private readonly hideOptionsRegexp =
-        /^(hide|show) (task count|backlink|priority|start date|scheduled date|done date|due date|recurrence rule|edit button|urgency)/;
+        /^(hide|show) (task count|backlink|priority|created date|start date|scheduled date|done date|due date|recurrence rule|edit button|urgency)/;
     private readonly shortModeRegexp = /^short/;
     private readonly explainQueryRegexp = /^explain/;
 
@@ -162,6 +162,9 @@ export class Query implements IQuery {
                 case 'priority':
                     this._layoutOptions.hidePriority = hide;
                     break;
+                case 'created date':
+                    this._layoutOptions.hideCreatedDate = hide;
+                    break;
                 case 'start date':
                     this._layoutOptions.hideStartDate = hide;
                     break;
diff --git a/src/Task.ts b/src/Task.ts
index 5d6b2963..3b6d2920 100644
--- a/src/Task.ts
+++ b/src/Task.ts
@@ -36,6 +36,7 @@ export const prioritySymbols = {
 
 export const recurrenceSymbol = '🔁';
 export const startDateSymbol = '🛫';
+export const createdDateSymbol = '➕';
 export const scheduledDateSymbol = '⏳';
 export const dueDateSymbol = '📅';
 export const doneDateSymbol = '✅';
@@ -92,6 +93,7 @@ export class TaskRegularExpressions {
     // removed from the end until none are left.
     public static readonly priorityRegex = /([⏫🔼🔽])$/u;
     public static readonly startDateRegex = /🛫 *(\d{4}-\d{2}-\d{2})$/u;
+    public static readonly createdDateRegex = /➕ *(\d{4}-\d{2}-\d{2})$/u;
     public static readonly scheduledDateRegex = /[⏳⌛] *(\d{4}-\d{2}-\d{2})$/u;
     public static readonly dueDateRegex = /[📅📆🗓] *(\d{4}-\d{2}-\d{2})$/u;
     public static readonly doneDateRegex = /✅ *(\d{4}-\d{2}-\d{2})$/u;
@@ -128,6 +130,7 @@ export class Task {
 
     public readonly priority: Priority;
 
+    public readonly createdDate: Moment | null;
     public readonly startDate: Moment | null;
     public readonly scheduledDate: Moment | null;
     public readonly dueDate: Moment | null;
@@ -154,6 +157,7 @@ export class Task {
         indentation,
         listMarker,
         priority,
+        createdDate,
         startDate,
         scheduledDate,
         dueDate,
@@ -170,6 +174,7 @@ export class Task {
         indentation: string;
         listMarker: string;
         priority: Priority;
+        createdDate: moment.Moment | null;
         startDate: moment.Moment | null;
         scheduledDate: moment.Moment | null;
         dueDate: moment.Moment | null;
@@ -190,6 +195,7 @@ export class Task {
 
         this.priority = priority;
 
+        this.createdDate = createdDate;
         this.startDate = startDate;
         this.scheduledDate = scheduledDate;
         this.dueDate = dueDate;
@@ -264,6 +270,7 @@ export class Task {
         let scheduledDateIsInferred = false;
         let dueDate: Moment | null = null;
         let doneDate: Moment | null = null;
+        let createdDate: Moment | null = null;
         let recurrenceRule: string = '';
         let recurrence: Recurrence | null = null;
         let tags: any = [];
@@ -323,6 +330,13 @@ export class Task {
                 matched = true;
             }
 
+            const createdDateMatch = description.match(TaskRegularExpressions.createdDateRegex);
+            if (createdDateMatch !== null) {
+                createdDate = window.moment(createdDateMatch[1], TaskRegularExpressions.dateFormat);
+                description = description.replace(TaskRegularExpressions.createdDateRegex, '').trim();
+                matched = true;
+            }
+
             const recurrenceMatch = description.match(TaskRegularExpressions.recurrenceRegex);
             if (recurrenceMatch !== null) {
                 // Save the recurrence rule, but *do not parse it yet*.
@@ -385,6 +399,7 @@ export class Task {
             listMarker,
             taskLocation: taskLocation,
             priority,
+            createdDate,
             startDate,
             scheduledDate,
             dueDate,
@@ -444,6 +459,11 @@ export class Task {
                 return layout.options.shortMode
                     ? ' ' + startDateSymbol
                     : ` ${startDateSymbol} ${this.startDate.format(TaskRegularExpressions.dateFormat)}`;
+            case 'createdDate':
+                if (!this.createdDate) return '';
+                return layout.options.shortMode
+                    ? ' ' + createdDateSymbol
+                    : ` ${createdDateSymbol} ${this.createdDate.format(TaskRegularExpressions.dateFormat)}`;
             case 'scheduledDate':
                 if (!this.scheduledDate || this.scheduledDateIsInferred) return '';
                 return layout.options.shortMode
@@ -522,6 +542,11 @@ export class Task {
         const newTasks: Task[] = [];
 
         if (nextOccurrence !== null) {
+            const { setCreatedDate } = getSettings();
+            let createdDate: moment.Moment | null = null;
+            if (setCreatedDate) {
+                createdDate = window.moment();
+            }
             const nextStatus = StatusRegistry.getInstance().getNextStatusOrCreate(newStatus);
             const nextTask = new Task({
                 ...this,
@@ -530,6 +555,8 @@ export class Task {
                 // New occurrences cannot have the same block link.
                 // And random block links don't help.
                 blockLink: '',
+                // add new createdDate on reccuring tasks
+                createdDate,
             });
             newTasks.push(nextTask);
         }
@@ -679,7 +706,7 @@ export class Task {
         }
 
         // Compare Date fields
-        args = ['startDate', 'scheduledDate', 'dueDate', 'doneDate'];
+        args = ['createdDate', 'startDate', 'scheduledDate', 'dueDate', 'doneDate'];
         for (const el of args) {
             const date1 = this[el] as Moment | null;
             const date2 = other[el] as Moment | null;
diff --git a/src/TaskLayout.ts b/src/TaskLayout.ts
index 29a0a1b9..8d7cb75e 100644
--- a/src/TaskLayout.ts
+++ b/src/TaskLayout.ts
@@ -5,6 +5,7 @@ export class LayoutOptions {
     hideTaskCount: boolean = false;
     hideBacklinks: boolean = false;
     hidePriority: boolean = false;
+    hideCreatedDate: boolean = false;
     hideStartDate: boolean = false;
     hideScheduledDate: boolean = false;
     hideDoneDate: boolean = false;
@@ -20,6 +21,7 @@ export type TaskLayoutComponent =
     | 'description'
     | 'priority'
     | 'recurrenceRule'
+    | 'createdDate'
     | 'startDate'
     | 'scheduledDate'
     | 'dueDate'
@@ -36,6 +38,7 @@ export class TaskLayout {
         'description',
         'priority',
         'recurrenceRule',
+        'createdDate',
         'startDate',
         'scheduledDate',
         'dueDate',
@@ -81,6 +84,7 @@ export class TaskLayout {
         let newComponents = this.layoutComponents;
         newComponents = removeIf(newComponents, layoutOptions.hidePriority, 'priority');
         newComponents = removeIf(newComponents, layoutOptions.hideRecurrenceRule, 'recurrenceRule');
+        newComponents = removeIf(newComponents, layoutOptions.hideCreatedDate, 'createdDate');
         newComponents = removeIf(newComponents, layoutOptions.hideStartDate, 'startDate');
         newComponents = removeIf(newComponents, layoutOptions.hideScheduledDate, 'scheduledDate');
         newComponents = removeIf(newComponents, layoutOptions.hideDueDate, 'dueDate');
diff --git a/src/TaskLineRenderer.ts b/src/TaskLineRenderer.ts
index 45e4846f..5997b695 100644
--- a/src/TaskLineRenderer.ts
+++ b/src/TaskLineRenderer.ts
@@ -177,6 +177,16 @@ function addTooltip({
             recurrenceDiv.setText(`${taskModule.recurrenceSymbol} ${task.recurrence.toText()}`);
         }
 
+        if (task.createdDate) {
+            const createdDateDiv = tooltip.createDiv();
+            createdDateDiv.setText(
+                toTooltipDate({
+                    signifier: taskModule.createdDateSymbol,
+                    date: task.createdDate,
+                }),
+            );
+        }
+
         if (task.startDate) {
             const startDateDiv = tooltip.createDiv();
             startDateDiv.setText(


Test patch:
diff --git a/tests/Query.test.ts b/tests/Query.test.ts
index c4c9dc49..0711c610 100644
--- a/tests/Query.test.ts
+++ b/tests/Query.test.ts
@@ -211,6 +211,7 @@ describe('Query parsing', () => {
             '# Comment lines are ignored',
             'explain',
             'hide backlink',
+            'hide created date',
             'hide done date',
             'hide due date',
             'hide edit button',
@@ -231,6 +232,7 @@ describe('Query parsing', () => {
             'show priority',
             'show recurrence rule',
             'show scheduled date',
+            'show created date',
             'show start date',
             'show task count',
             'show urgency',
@@ -293,6 +295,7 @@ describe('Query', () => {
                     tags: [],
                     originalMarkdown: '',
                     scheduledDateIsInferred: false,
+                    createdDate: null,
                 }),
                 new Task({
                     status: Status.TODO,
@@ -310,6 +313,7 @@ describe('Query', () => {
                     tags: [],
                     originalMarkdown: '',
                     scheduledDateIsInferred: false,
+                    createdDate: null,
                 }),
             ];
             const input = 'path includes ab/c d';
diff --git a/tests/Task.test.ts b/tests/Task.test.ts
index 8fb0c093..be26b418 100644
--- a/tests/Task.test.ts
+++ b/tests/Task.test.ts
@@ -19,7 +19,7 @@ window.moment = moment;
 describe('parsing', () => {
     it('parses a task from a line starting with hyphen', () => {
         // Arrange
-        const line = '- [x] this is a done task 🗓 2021-09-12 ✅ 2021-06-20';
+        const line = '- [x] this is a done task 🗓 2021-09-12 ✅ 2021-06-20 ➕ 2023-03-07';
 
         // Act
         const task = fromLine({
@@ -31,6 +31,8 @@ describe('parsing', () => {
         expect(task!.listMarker).toEqual('-');
         expect(task!.description).toEqual('this is a done task');
         expect(task!.status).toStrictEqual(Status.DONE);
+        expect(task!.createdDate).not.toBeNull();
+        expect(task!.createdDate!.isSame(moment('2023-03-07', 'YYYY-MM-DD'))).toStrictEqual(true);
         expect(task!.dueDate).not.toBeNull();
         expect(task!.dueDate!.isSame(moment('2021-09-12', 'YYYY-MM-DD'))).toStrictEqual(true);
         expect(task!.doneDate).not.toBeNull();
@@ -208,9 +210,10 @@ describe('parsing', () => {
     it('supports parsing of emojis with multiple spaces', () => {
         // Arrange
         const lines = [
-            '- [ ] Wobble ✅2022-07-01 📅2022-07-02 ⏳2022-07-03 🛫2022-07-04 🔁every day',
-            '- [ ] Wobble ✅ 2022-07-01 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
-            '- [ ] Wobble ✅  2022-07-01 📅  2022-07-02 ⏳  2022-07-03 🛫  2022-07-04 🔁  every day',
+            '- [ ] Wobble ✅2022-07-01 📅2022-07-02 ⏳2022-07-03 🛫2022-07-04 ➕2022-07-05 🔁every day',
+            '- [ ] Wobble ✅ 2022-07-01 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 ➕ 2022-07-05 🔁 every day',
+            '- [ ] Wobble ✅  2022-07-01 📅  2022-07-02 ⏳  2022-07-03 🛫  2022-07-04 ➕  2022-07-05 🔁  every day',
+            '- [ ] Wobble ✅  2022-07-01 📅  2022-07-02 ⏳  2022-07-03 🛫  2022-07-04 ➕   2022-07-05 🔁  every day',
         ];
         // Act
         for (const line of lines) {
@@ -226,6 +229,7 @@ describe('parsing', () => {
                 due: task.dueDate?.format('YYYY-MM-DD'),
                 scheduled: task.scheduledDate?.format('YYYY-MM-DD'),
                 start: task.startDate?.format('YYYY-MM-DD'),
+                created: task.createdDate?.format('YYYY-MM-DD'),
                 priority: task.priority,
                 recurrence: task.recurrence?.toText(),
             }).toMatchObject({
@@ -235,6 +239,7 @@ describe('parsing', () => {
                 due: '2022-07-02',
                 scheduled: '2022-07-03',
                 start: '2022-07-04',
+                created: '2022-07-05',
                 priority: '3',
                 recurrence: 'every day',
             });
@@ -923,6 +928,110 @@ describe('toggle done', () => {
     });
 });
 
+describe('set correct created date on reccurence task', () => {
+    it('does not set created date with disabled setting', () => {
+        // Arrange
+        const line = '- [ ] this is a task 📅 2021-09-12 🔁 every day';
+        updateSettings({ setCreatedDate: false });
+
+        // Act
+        const task = fromLine({
+            line,
+        });
+
+        // Assert
+        expect(task).not.toBeNull();
+        expect(task!.createdDate).toBeNull();
+
+        const tasks = task!.toggle();
+        expect(tasks.length).toEqual(2);
+        const nextTask: Task = tasks[0];
+        expect(nextTask.createdDate).toBeNull();
+
+        // cleanup
+        resetSettings();
+    });
+
+    it('does not set created date with disabled setting when repeated has created date', () => {
+        // Arrange
+        const line = '- [ ] this is a task ➕ 2021-09-11 📅 2021-09-12 🔁 every day';
+        updateSettings({ setCreatedDate: false });
+
+        // Act
+        const task = fromLine({
+            line,
+        });
+
+        // Assert
+        expect(task).not.toBeNull();
+        expect(task!.createdDate).not.toBeNull();
+        expect(task!.createdDate!.isSame(moment('2021-09-11', 'YYYY-MM-DD'))).toStrictEqual(true);
+
+        const tasks = task!.toggle();
+        expect(tasks.length).toEqual(2);
+        const nextTask: Task = tasks[0];
+        expect(nextTask.createdDate).toBeNull();
+
+        // cleanup
+        resetSettings();
+    });
+
+    it('set created date with enabled setting', () => {
+        // Arrange
+        const today = '2023-03-08';
+        const todaySpy = jest.spyOn(Date, 'now').mockReturnValue(moment(today).valueOf());
+        const line = '- [ ] this is a task 📅 2021-09-12 🔁 every day';
+        updateSettings({ setCreatedDate: true });
+
+        // Act
+        const task = fromLine({
+            line,
+        });
+
+        // Assert
+        expect(task).not.toBeNull();
+        expect(task!.createdDate).toBeNull();
+
+        const tasks = task!.toggle();
+        expect(tasks.length).toEqual(2);
+        const nextTask: Task = tasks[0];
+        expect(nextTask.createdDate).not.toBeNull();
+        expect(nextTask!.createdDate!.isSame(moment(today, 'YYYY-MM-DD'))).toStrictEqual(true);
+
+        // cleanup
+        resetSettings();
+        todaySpy.mockClear();
+    });
+
+    it('set created date with enabled setting when repeated has created date', () => {
+        // Arrange
+        const today = '2023-03-08';
+        const todaySpy = jest.spyOn(Date, 'now').mockReturnValue(moment(today).valueOf());
+        const line = '- [ ] this is a task ➕ 2021-09-11 📅 2021-09-12 🔁 every day';
+        updateSettings({ setCreatedDate: true });
+
+        // Act
+        const task = fromLine({
+            line,
+        });
+
+        // Assert
+        expect(task).not.toBeNull();
+        expect(task!.createdDate).not.toBeNull();
+        expect(task!.createdDate!.isSame(moment('2021-09-11', 'YYYY-MM-DD'))).toStrictEqual(true);
+
+        const tasks = task!.toggle();
+        expect(tasks.length).toEqual(2);
+        const nextTask: Task = tasks[0];
+        expect(nextTask.createdDate).not.toBeNull();
+        expect(nextTask!.createdDate!.isSame(moment(today, 'YYYY-MM-DD'))).toStrictEqual(true);
+
+        // cleanup
+        resetSettings();
+        todaySpy.mockClear();
+    });
+});
+
 declare global {
     namespace jest {
         interface Matchers<R> {
@@ -1026,6 +1135,13 @@ describe('identicalTo', () => {
         expect(lhs).not.toBeIdenticalTo(new TaskBuilder().priority(Priority.None));
     });
 
+    it('should check createdDate', () => {
+        const lhs = new TaskBuilder().createdDate('2012-12-27');
+        expect(lhs).toBeIdenticalTo(new TaskBuilder().createdDate('2012-12-27'));
+        expect(lhs).not.toBeIdenticalTo(new TaskBuilder().createdDate(null));
+        expect(lhs).not.toBeIdenticalTo(new TaskBuilder().createdDate('2012-12-26'));
+    });
+
     it('should check startDate', () => {
         const lhs = new TaskBuilder().startDate('2012-12-27');
         expect(lhs).toBeIdenticalTo(new TaskBuilder().startDate('2012-12-27'));
diff --git a/tests/TaskLineRenderer.test.ts b/tests/TaskLineRenderer.test.ts
index 42af0bf0..550e0aeb 100644
--- a/tests/TaskLineRenderer.test.ts
+++ b/tests/TaskLineRenderer.test.ts
@@ -127,6 +127,14 @@ describe('task line rendering', () => {
         );
     });
 
+    it('renders without created date', async () => {
+        await testLayoutOptions(
+            '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 ➕ 2022-07-05 🔁 every day',
+            { hideCreatedDate: true },
+            'Full task ⏫ 🔁 every day 🛫 2022-07-04 ⏳ 2022-07-03 📅 2022-07-02',
+        );
+    });
+
     it('renders without start date', async () => {
         await testLayoutOptions(
             '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
diff --git a/tests/TestingTools/TaskBuilder.ts b/tests/TestingTools/TaskBuilder.ts
index 72e2bfb2..fc1d7c0c 100644
--- a/tests/TestingTools/TaskBuilder.ts
+++ b/tests/TestingTools/TaskBuilder.ts
@@ -34,6 +34,7 @@ export class TaskBuilder {
     private _tags: string[] = [];
     private _priority: Priority = Priority.None;
 
+    private _createdDate: Moment | null = null;
     private _startDate: Moment | null = null;
     private _scheduledDate: Moment | null = null;
     private _dueDate: Moment | null = null;
@@ -74,6 +75,7 @@ export class TaskBuilder {
             indentation: this._indentation,
             listMarker: this._listMarker,
             priority: this._priority,
+            createdDate: this._createdDate,
             startDate: this._startDate,
             scheduledDate: this._scheduledDate,
             dueDate: this._dueDate,
@@ -167,6 +169,11 @@ export class TaskBuilder {
         return this;
     }
 
+    public createdDate(createdDate: string | null): TaskBuilder {
+        this._createdDate = TaskBuilder.parseDate(createdDate);
+        return this;
+    }
+
     public startDate(startDate: string | null): TaskBuilder {
         this._startDate = TaskBuilder.parseDate(startDate);
         return this;