diff --git a/pkg/container/types/date.go b/pkg/container/types/date.go
index 05aa5b79475d7841a55e07795fcaccf39b4930c3..9018ca9825390dce88ff4d3f91807b75fac9243b 100644
--- a/pkg/container/types/date.go
+++ b/pkg/container/types/date.go
@@ -373,3 +373,10 @@ func (d Date) Month() uint8 {
 	_, month, _, _ := d.Calendar(true)
 	return month
 }
+
+func LastDay(year uint16, month uint8) int {
+	if isLeap(int32(year)) {
+		return int(leapYearMonthDays[month-1])
+	}
+	return int(flatYearMonthDays[month-1])
+}
diff --git a/pkg/container/types/datetime.go b/pkg/container/types/datetime.go
index 2646c4be5ee012d5c26f5f6092e6b90b8a08d9eb..2db8eea4e76317439783cf930044c01a52af914f 100644
--- a/pkg/container/types/datetime.go
+++ b/pkg/container/types/datetime.go
@@ -16,8 +16,9 @@ package types
 
 import (
 	"fmt"
+	"math"
 	"strconv"
-	"time"
+	gotime "time"
 	"unsafe"
 
 	"github.com/matrixorigin/matrixone/pkg/errno"
@@ -29,14 +30,21 @@ const (
 	secsPerHour   = 60 * secsPerMinute
 	secsPerDay    = 24 * secsPerHour
 	//secsPerWeek   = 7 * secsPerDay
+	microSecondBitMask = 0xfffff
 )
 
 // The higher 44 bits holds number of seconds since January 1, year 1 in Gregorian
 // calendar, and lower 20 bits holds number of microseconds
 
 func (dt Datetime) String() string {
+	// when datetime have microsecond, we print it, default precision is 6
 	y, m, d, _ := dt.ToDate().Calendar(true)
 	hour, minute, sec := dt.Clock()
+	msec := int64(dt) & microSecondBitMask
+	if msec > 0 {
+		msecInstr := fmt.Sprintf("%06d", msec)
+		return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d"+"."+msecInstr, y, m, d, hour, minute, sec)
+	}
 	return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", y, m, d, hour, minute, sec)
 }
 
@@ -60,6 +68,8 @@ var (
 // 1. all the Date value
 // 2. yyyy-mm-dd hh:mm:ss(.msec)
 // 3. yyyymmddhhmmss(.msec)
+// Notice: 2022-01-01 00:00:00.1 and 20220101000000.1 should parse to 100000 microsecond instead of 1 microsecond
+// I call the situation is microsecond number bug
 func ParseDatetime(s string) (Datetime, error) {
 	if len(s) < 14 {
 		if d, err := ParseDate(s); err == nil {
@@ -105,6 +115,8 @@ func ParseDatetime(s string) (Datetime, error) {
 				if err != nil {
 					return -1, errIncorrectDatetimeValue
 				}
+				// fix microsecond number bug
+				m = m * uint64(math.Pow10(26-len(s)))
 				msec = uint32(m)
 			} else {
 				return -1, errIncorrectDatetimeValue
@@ -122,6 +134,8 @@ func ParseDatetime(s string) (Datetime, error) {
 				if err != nil {
 					return -1, errIncorrectDatetimeValue
 				}
+				// fix microsecond number bug
+				m = m * uint64(math.Pow10(21-len(s)))
 				msec = uint32(m)
 			} else {
 				return -1, errIncorrectDatetimeValue
@@ -159,7 +173,7 @@ func FromUnix(time int64) Datetime {
 }
 
 func Now() Datetime {
-	t := time.Now()
+	t := gotime.Now()
 	wall := *(*uint64)(unsafe.Pointer(&t))
 	ext := *(*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(&t)) + unsafe.Sizeof(wall)))
 	var sec, nsec int64
@@ -191,6 +205,63 @@ func FromClock(year int32, month, day, hour, min, sec uint8, msec uint32) Dateti
 	return Datetime((secs << 20) + int64(msec))
 }
 
+func (dt Datetime) ConvertToGoTime() gotime.Time {
+	y, m, d, _ := dt.ToDate().Calendar(true)
+	msec := dt.microSec()
+	hour, min, sec := dt.Clock()
+	return gotime.Date(int(y), gotime.Month(m), int(d), int(hour), int(min), int(sec), int(msec*1000), startupTime.Location())
+}
+
+func (dt Datetime) AddDateTime(date gotime.Time, addMsec, addSec, addMin, addHour, addDay, addMonth, addYear int64) Datetime {
+	date = date.Add(gotime.Duration(addMsec) * gotime.Microsecond)
+	date = date.Add(gotime.Duration(addSec) * gotime.Second)
+	date = date.Add(gotime.Duration(addMin) * gotime.Minute)
+	date = date.Add(gotime.Duration(addHour) * gotime.Hour)
+	// corner case: mysql: date_add('2022-01-31',interval 1 month) -> 2022-02-28
+	// only in the month year year-month
+	if addMonth != 0 || addYear != 0 {
+		originDay := date.Day()
+		newDate := date.AddDate(int(addYear), int(addMonth), int(addDay))
+		newDay := newDate.Day()
+		if originDay != newDay {
+			maxDay := LastDay(uint16(newDate.Year()), uint8(newDate.Month()-1))
+			addDay = int64(maxDay) - int64(originDay)
+		}
+	}
+	date = date.AddDate(int(addYear), int(addMonth), int(addDay))
+	return FromClock(int32(date.Year()), uint8(date.Month()), uint8(date.Day()), uint8(date.Hour()), uint8(date.Minute()), uint8(date.Second()), uint32(date.Nanosecond()/1000))
+}
+
+func (dt Datetime) AddInterval(nums int64, its IntervalType) Datetime {
+	goTime := dt.ConvertToGoTime()
+	var addMsec, addSec, addMin, addHour, addDay, addMonth, addYear int64
+	switch its {
+	case MicroSecond:
+		addMsec += nums
+	case Second:
+		addSec += nums
+	case Minute:
+		addMin += nums
+	case Hour:
+		addHour += nums
+	case Day:
+		addDay += nums
+	case Week:
+		addDay += 7 * nums
+	case Month:
+		addMonth += nums
+	case Quarter:
+		addMonth += 3 * nums
+	case Year:
+		addYear += nums
+	}
+	return dt.AddDateTime(goTime, addMsec, addSec, addMin, addHour, addDay, addMonth, addYear)
+}
+
+func (dt Datetime) microSec() int64 {
+	return int64(dt) << 44 >> 44
+}
+
 func (dt Datetime) sec() int64 {
 	return int64(dt) >> 20
 }
diff --git a/pkg/container/types/datetime_test.go b/pkg/container/types/datetime_test.go
index 37e35f01cf2eaa3ff5daa08990a338d15cd43941..f05387f52b192a7b4a7a196fa82d968200f69ebc 100644
--- a/pkg/container/types/datetime_test.go
+++ b/pkg/container/types/datetime_test.go
@@ -16,6 +16,7 @@ package types
 
 import (
 	"fmt"
+	"github.com/stretchr/testify/require"
 	"testing"
 	"time"
 )
@@ -67,6 +68,98 @@ func TestDatetime(t *testing.T) {
 	fmt.Println(dt.Clock())
 }
 
+func TestAddDatetime(t *testing.T) {
+	addDateTimeTbl := []struct {
+		Input              string
+		InputIntervalNum   string
+		InputIntervalTypes IntervalType
+		expect             string
+	}{
+		{"2022-01-31 00:00:00", "1", MicroSecond, "2022-01-31 00:00:00.000001"},
+		{"2022-01-31 00:00:00.000001", "1", MicroSecond, "2022-01-31 00:00:00.000002"},
+		{"2022-01-31 00:00:00", "1", Second, "2022-01-31 00:00:01"},
+		{"2022-01-31 00:00:00", "1", Minute, "2022-01-31 00:01:00"},
+		{"2022-01-31 00:00:00", "1", Hour, "2022-01-31 01:00:00"},
+		{"2022-01-31 00:00:00", "1", Day, "2022-02-01 00:00:00"},
+		{"2022-01-31 00:00:00", "1", Week, "2022-02-07 00:00:00"},
+		{"2022-01-01 00:00:00", "1", Month, "2022-02-01 00:00:00"},
+		{"2022-01-31 00:00:00", "1", Month, "2022-02-28 00:00:00"},
+		{"2022-01-01 00:00:00", "1", Quarter, "2022-04-01 00:00:00"},
+		{"2022-01-31 00:00:00", "1", Quarter, "2022-04-30 00:00:00"},
+		{"2022-01-01 00:00:00", "1", Year, "2023-01-01 00:00:00"},
+		{"2020-02-29 00:00:00", "1", Year, "2021-02-28 00:00:00"},
+
+		{"2022-01-01 00:00:00", "1.1", Second_MicroSecond, "2022-01-01 00:00:01.100000"},
+		{"2022-01-01 00:00:00", "1:1.1", Minute_MicroSecond, "2022-01-01 00:01:01.100000"},
+		{"2022-01-01 00:00:00", "1:1", Minute_Second, "2022-01-01 00:01:01"},
+		{"2022-01-01 00:00:00", "1:1:1.1", Hour_MicroSecond, "2022-01-01 01:01:01.100000"},
+		{"2022-01-01 00:00:00", "1:1:1", Hour_Second, "2022-01-01 01:01:01"},
+		{"2022-01-01 00:00:00", "1:1", Hour_Minute, "2022-01-01 01:01:00"},
+		{"2022-01-01 00:00:00", "1 1:1:1.1", Day_MicroSecond, "2022-01-02 01:01:01.100000"},
+		{"2022-01-01 00:00:00", "1 1:1:1", Day_Second, "2022-01-02 01:01:01"},
+		{"2022-01-01 00:00:00", "1 1:1", Day_Minute, "2022-01-02 01:01:00"},
+		{"2022-01-01 00:00:00", "1 1", Day_Hour, "2022-01-02 01:00:00"},
+		{"2022-01-01 00:00:00", "1-1", Year_Month, "2023-02-01 00:00:00"},
+
+		{"2022-01-31 00:00:00", "1-1", Year_Month, "2023-02-28 00:00:00"},
+
+		{"2020-12-31 23:59:59", "1", Second, "2021-01-01 00:00:00"},
+		{"2100-12-31 23:59:59", "1:1", Minute_Second, "2101-01-01 00:01:00"},
+		{"1992-12-31 23:59:59.000002", "1.999999", Second_MicroSecond, "1993-01-01 00:00:01.000001"},
+		{"1992-12-31 23:59:59.1", "1.1", Second_MicroSecond, "1993-01-01 00:00:00.200000"},
+	}
+	for _, test := range addDateTimeTbl {
+		ret, rettype, _ := NormalizeInterval(test.InputIntervalNum, test.InputIntervalTypes)
+		d, err := ParseDatetime(test.Input)
+		require.Equal(t, err, nil)
+		d = d.AddInterval(ret, rettype)
+		require.Equal(t, d.String(), test.expect)
+	}
+}
+
+func TestSubDateTime(t *testing.T) {
+	subDateTimeTbl := []struct {
+		Input              string
+		InputIntervalNum   string
+		InputIntervalTypes IntervalType
+		expect             string
+	}{
+		{"2022-01-31 00:00:00", "1", MicroSecond, "2022-01-30 23:59:59.999999"},
+		{"2022-01-31 00:00:00.000001", "1", MicroSecond, "2022-01-31 00:00:00"},
+		{"2022-01-31 00:00:00", "1", Second, "2022-01-30 23:59:59"},
+		{"2022-01-31 00:00:00", "1", Minute, "2022-01-30 23:59:00"},
+		{"2022-01-31 00:00:00", "1", Hour, "2022-01-30 23:00:00"},
+		{"2022-01-31 00:00:00", "1", Day, "2022-01-30 00:00:00"},
+		{"2022-01-31 00:00:00", "1", Week, "2022-01-24 00:00:00"},
+		{"2022-01-01 00:00:00", "1", Month, "2021-12-01 00:00:00"},
+		{"2022-03-31 00:00:00", "1", Month, "2022-02-28 00:00:00"},
+		{"2022-01-01 00:00:00", "1", Quarter, "2021-10-01 00:00:00"},
+		{"2022-01-31 00:00:00", "1", Quarter, "2021-10-31 00:00:00"},
+		{"2022-01-01 00:00:00", "1", Year, "2021-01-01 00:00:00"},
+		{"2020-02-29 00:00:00", "1", Year, "2019-02-28 00:00:00"},
+
+		{"2022-01-01 00:00:00", "1.1", Second_MicroSecond, "2021-12-31 23:59:58.900000"},
+		{"2022-01-01 00:00:00", "1:1.1", Minute_MicroSecond, "2021-12-31 23:58:58.900000"},
+		{"2022-01-01 00:00:00", "1:1", Minute_Second, "2021-12-31 23:58:59"},
+		{"2022-01-01 00:00:00", "1:1:1.1", Hour_MicroSecond, "2021-12-31 22:58:58.900000"},
+		{"2022-01-01 00:00:00", "1:1:1", Hour_Second, "2021-12-31 22:58:59"},
+		{"2022-01-01 00:00:00", "1:1", Hour_Minute, "2021-12-31 22:59:00"},
+		{"2022-01-01 00:00:00", "1 1:1:1.1", Day_MicroSecond, "2021-12-30 22:58:58.900000"},
+		{"2022-01-01 00:00:00", "1 1:1:1", Day_Second, "2021-12-30 22:58:59"},
+		{"2022-01-01 00:00:00", "1 1:1", Day_Minute, "2021-12-30 22:59:00"},
+		{"2022-01-01 00:00:00", "1 1", Day_Hour, "2021-12-30 23:00:00"},
+		{"2022-01-01 00:00:00", "1-1", Year_Month, "2020-12-01 00:00:00"},
+		{"2022-01-31 00:00:00.1", "1", Second, "2022-01-30 23:59:59.100000"},
+	}
+	for _, test := range subDateTimeTbl {
+		ret, rettype, _ := NormalizeInterval(test.InputIntervalNum, test.InputIntervalTypes)
+		d, err := ParseDatetime(test.Input)
+		require.Equal(t, err, nil)
+		d = d.AddInterval(-ret, rettype)
+		require.Equal(t, d.String(), test.expect)
+	}
+}
+
 func TestParseDatetime(t *testing.T) {
 	tests := []struct {
 		name    string
@@ -83,7 +176,7 @@ func TestParseDatetime(t *testing.T) {
 		{
 			name: "yyyy-mm-dd hh:mm:ss.sec",
 			args: "1987-08-25 00:00:00.1",
-			want: "1987-08-25 00:00:00",
+			want: "1987-08-25 00:00:00.100000",
 		},
 		// 2. yyyymmddhhmmss(.msec)
 		{
@@ -94,7 +187,7 @@ func TestParseDatetime(t *testing.T) {
 		{
 			name: "yyyymmddhhmmss.sec",
 			args: "19870825000000.5",
-			want: "1987-08-25 00:00:00",
+			want: "1987-08-25 00:00:00.500000",
 		},
 		// 3. out of range
 		{
diff --git a/pkg/container/types/interval.go b/pkg/container/types/interval.go
index 0c01521b958fa89e7561bbc4e00119169e2202d6..4a934ef28c0ff5857dd2e2dc8268ad8b82d1fe5e 100644
--- a/pkg/container/types/interval.go
+++ b/pkg/container/types/interval.go
@@ -15,6 +15,7 @@
 package types
 
 import (
+	"math"
 	"strings"
 
 	"github.com/matrixorigin/matrixone/pkg/errno"
@@ -111,21 +112,34 @@ func IntervalTypeOf(s string) (IntervalType, error) {
 
 //
 // parseInts parse integer from string s.   This is used to handle interval values,
+// when interval type is Second_MicroSecond Minute_MicroSecond Hour_MicroSecond Day_MicroSecond
+// we should set second parameter true, other set false
+// the example: when the s is "1:1"
+// when we use Second_MicroSecond(...), we should parse to 1 second and 100000 microsecond.
+// when we use Minute_Second(...), we just parse to 1 minute and 1 second.
+// so we use method to solve this: we count the length of the num, use 1e(6 - length) * ret[len(ret) - 1]
+// for example: when the s is "1:001"
+// the last number length is 3, so the last number should be 1e(6 - 3) * 1 = 1000
+// typeMaxLength means when I use Second_MicroSecond, the typeMaxLength is 2
+// when s is "1", we don't think number 1 is microsecond
 // so there are a few strange things.
 //	1. Only takes 0-9, may have leading 0, still means decimal instead oct.
 //  2. 1-1 is parsed out as 1, 1 '-' is delim, so is '+', '.' etc.
 //	3. we will not support int32 overflow.
 //
-func parseInts(s string) ([]int32, error) {
+func parseInts(s string, isxxxMicrosecond bool, typeMaxLength int) ([]int32, error) {
 	ret := make([]int32, 0)
+	numLength := 0
 	cur := -1
 	for _, c := range s {
 		if c >= rune('0') && c <= rune('9') {
 			if cur < 0 {
 				cur = len(ret)
 				ret = append(ret, c-rune('0'))
+				numLength++
 			} else {
 				ret[cur] = 10*ret[cur] + c - rune('0')
+				numLength++
 				if ret[cur] < 0 {
 					return nil, errors.New(errno.DataException, "Invalid string interval value")
 				}
@@ -133,9 +147,15 @@ func parseInts(s string) ([]int32, error) {
 		} else {
 			if cur >= 0 {
 				cur = -1
+				numLength = 0
 			}
 		}
 	}
+	if isxxxMicrosecond {
+		if len(ret) == typeMaxLength {
+			ret[len(ret)-1] *= int32(math.Pow10(6 - numLength))
+		}
+	}
 	return ret, nil
 }
 
@@ -158,7 +178,7 @@ func conv(a []int32, mul []int64, rt IntervalType) (int64, IntervalType, error)
 }
 
 func NormalizeInterval(s string, it IntervalType) (ret int64, rettype IntervalType, err error) {
-	vals, err := parseInts(s)
+	vals, err := parseInts(s, isxxxMicrosecondType(it), typeMaxLength(it))
 	if err != nil {
 		return
 	}
@@ -202,3 +222,49 @@ func NormalizeInterval(s string, it IntervalType) (ret int64, rettype IntervalTy
 	}
 	return
 }
+
+func isxxxMicrosecondType(it IntervalType) bool {
+	return it == Second_MicroSecond || it == Minute_MicroSecond || it == Hour_MicroSecond || it == Day_MicroSecond
+}
+
+func typeMaxLength(it IntervalType) int {
+	switch it {
+	case MicroSecond, Second, Minute, Hour, Day,
+		Week, Month, Quarter, Year:
+		return 1
+
+	case Second_MicroSecond:
+		return 2
+
+	case Minute_MicroSecond:
+		return 3
+
+	case Minute_Second:
+		return 2
+
+	case Hour_MicroSecond:
+		return 4
+
+	case Hour_Second:
+		return 3
+
+	case Hour_Minute:
+		return 2
+
+	case Day_MicroSecond:
+		return 5
+
+	case Day_Second:
+		return 4
+
+	case Day_Minute:
+		return 3
+
+	case Day_Hour:
+		return 2
+
+	case Year_Month:
+		return 2
+	}
+	return 0
+}
diff --git a/pkg/container/types/interval_test.go b/pkg/container/types/interval_test.go
index 867f01d99586e2263af5c173d8ad05d9cda12d42..ad235e7ddcc0167a52170e6824845ff2ab315521 100644
--- a/pkg/container/types/interval_test.go
+++ b/pkg/container/types/interval_test.go
@@ -115,12 +115,12 @@ func TestConv(t *testing.T) {
 
 	val, vt, err = NormalizeInterval("1 01:02:03.4", Day_MicroSecond)
 	val2, vt2, _ := NormalizeInterval("1 01:02:03", Day_MicroSecond)
-	val3, vt3, _ := NormalizeInterval("0 00:00:00.04", Day_MicroSecond)
+	val3, vt3, _ := NormalizeInterval("0 00:00:00.4", Day_MicroSecond)
 	require.Equal(t, err, nil, "HM error")
 	require.Equal(t, vt, MicroSecond, "D_US error")
 	require.Equal(t, vt, vt2, "D_US error")
 	require.Equal(t, vt, vt3, "D_US error")
-	require.Equal(t, val3, int64(4), "D_US error")
+	require.Equal(t, val3, int64(400000), "D_US error")
 	require.Equal(t, val2, int64(24*60*60*1000000+1*60*60*1000000+2*60*1000000+3*1000000), "D_US error")
 	require.Equal(t, val, val2+val3, "D_US error")
 
diff --git a/pkg/sql/plan2/build_test.go b/pkg/sql/plan2/build_test.go
index f715e0a40781c8b8d7a8d3ce021c43f3e65aba94..635e05ea7582d38a17f1a86fa86fcd527fa14dc3 100644
--- a/pkg/sql/plan2/build_test.go
+++ b/pkg/sql/plan2/build_test.go
@@ -30,7 +30,11 @@ import (
 func TestSingleSql(t *testing.T) {
 	// sql := "SELECT * FROM NATION where n_nationkey > 10"
 	// sql := "SELECT COUNT(n_nationkey) FROM NATION"
-	sql := "SELECT COUNT(*) FROM NATION a"
+	// sql := "SELECT COUNT(*) FROM NATION a"
+	// sql := "SELECT DATE_ADD('2022-01-31', INTERVAL 1 day) FROM NATION a"
+	// sql := "SELECT DATE_ADD(date '2022-01-31', INTERVAL 1 day) FROM NATION"
+	sql := "SELECT DATE_SUB(date '2022-01-31', INTERVAL 1 day) FROM NATION"
+	// sql := "SELECT date'2022-01-31' + INTERVAL 114 day FROM NATION a"
 	// sql := "SELECT n_nationkey, COUNT(*) AS TTT FROM NATION group by n_nationkey"
 	// sql := "select * from (select * from NATION order by n_nationkey) as x where n_nationkey > 10"
 	// sql := `select * from (select * from NATION order by n_nationkey) as x`
diff --git a/pkg/sql/plan2/function/builtin/unary/date_add.go b/pkg/sql/plan2/function/builtin/unary/date_add.go
new file mode 100644
index 0000000000000000000000000000000000000000..10357d2417bdb1d88373c31e1f1f5ebc08a42ab0
--- /dev/null
+++ b/pkg/sql/plan2/function/builtin/unary/date_add.go
@@ -0,0 +1,80 @@
+// Copyright 2022 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package unary
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	"github.com/matrixorigin/matrixone/pkg/vectorize/date_add"
+	"github.com/matrixorigin/matrixone/pkg/vm/process"
+)
+
+func DateAdd(vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
+	firstVector := vectors[0]
+	secondVector := vectors[1]
+	thirdVector := vectors[2]
+	firstValues, secondValues, thirdValues := firstVector.Col.([]types.Date), secondVector.Col.([]int64), thirdVector.Col.([]int64)
+	resultType := types.Type{Oid: types.T_date, Size: 4}
+	resultElementSize := int(resultType.Size)
+	if firstVector.IsScalar() {
+		if firstVector.ConstVectorIsNull() {
+			return proc.AllocScalarNullVector(resultType), nil
+		}
+		resultVector := vector.NewConst(resultType)
+		resultValues := make([]types.Date, 1)
+		vector.SetCol(resultVector, date_add.DateAdd(firstValues, secondValues, thirdValues, resultValues))
+		return resultVector, nil
+	} else {
+		resultVector, err := proc.AllocVector(resultType, int64(resultElementSize*len(firstValues)))
+		if err != nil {
+			return nil, err
+		}
+		resultValues := encoding.DecodeDateSlice(resultVector.Data)
+		resultValues = resultValues[:len(firstValues)]
+		nulls.Set(resultVector.Nsp, firstVector.Nsp)
+		vector.SetCol(resultVector, date_add.DateAdd(firstValues, secondValues, thirdValues, resultValues))
+		return resultVector, nil
+	}
+}
+
+func DatetimeAdd(vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
+	firstVector := vectors[0]
+	secondVector := vectors[1]
+	thirdVector := vectors[2]
+	firstValues, secondValues, thirdValues := firstVector.Col.([]types.Datetime), secondVector.Col.([]int64), thirdVector.Col.([]int64)
+	resultType := types.Type{Oid: types.T_datetime, Size: 8}
+	resultElementSize := int(resultType.Size)
+	if firstVector.IsScalar() {
+		if firstVector.ConstVectorIsNull() {
+			return proc.AllocScalarNullVector(resultType), nil
+		}
+		resultVector := vector.NewConst(resultType)
+		resultValues := make([]types.Datetime, 1)
+		vector.SetCol(resultVector, date_add.DatetimeAdd(firstValues, secondValues, thirdValues, resultValues))
+		return resultVector, nil
+	} else {
+		resultVector, err := proc.AllocVector(resultType, int64(resultElementSize*len(firstValues)))
+		if err != nil {
+			return nil, err
+		}
+		resultValues := encoding.DecodeDatetimeSlice(resultVector.Data)
+		resultValues = resultValues[:len(firstValues)]
+		nulls.Set(resultVector.Nsp, firstVector.Nsp)
+		vector.SetCol(resultVector, date_add.DatetimeAdd(firstValues, secondValues, thirdValues, resultValues))
+		return resultVector, nil
+	}
+}
diff --git a/pkg/sql/plan2/function/builtin/unary/date_sub.go b/pkg/sql/plan2/function/builtin/unary/date_sub.go
new file mode 100644
index 0000000000000000000000000000000000000000..27ac6a96b87290ba51497f532db85bd5aaf0cd70
--- /dev/null
+++ b/pkg/sql/plan2/function/builtin/unary/date_sub.go
@@ -0,0 +1,80 @@
+// Copyright 2022 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package unary
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	"github.com/matrixorigin/matrixone/pkg/vectorize/date_sub"
+	"github.com/matrixorigin/matrixone/pkg/vm/process"
+)
+
+func DateSub(vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
+	firstVector := vectors[0]
+	secondVector := vectors[1]
+	thirdVector := vectors[2]
+	firstValues, secondValues, thirdValues := firstVector.Col.([]types.Date), secondVector.Col.([]int64), thirdVector.Col.([]int64)
+	resultType := types.Type{Oid: types.T_date, Size: 4}
+	resultElementSize := int(resultType.Size)
+	if firstVector.IsScalar() {
+		if firstVector.ConstVectorIsNull() {
+			return proc.AllocScalarNullVector(resultType), nil
+		}
+		resultVector := vector.NewConst(resultType)
+		resultValues := make([]types.Date, 1)
+		vector.SetCol(resultVector, date_sub.DateSub(firstValues, secondValues, thirdValues, resultValues))
+		return resultVector, nil
+	} else {
+		resultVector, err := proc.AllocVector(resultType, int64(resultElementSize*len(firstValues)))
+		if err != nil {
+			return nil, err
+		}
+		resultValues := encoding.DecodeDateSlice(resultVector.Data)
+		resultValues = resultValues[:len(firstValues)]
+		nulls.Set(resultVector.Nsp, firstVector.Nsp)
+		vector.SetCol(resultVector, date_sub.DateSub(firstValues, secondValues, thirdValues, resultValues))
+		return resultVector, nil
+	}
+}
+
+func DatetimeSub(vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
+	firstVector := vectors[0]
+	secondVector := vectors[1]
+	thirdVector := vectors[2]
+	firstValues, secondValues, thirdValues := firstVector.Col.([]types.Datetime), secondVector.Col.([]int64), thirdVector.Col.([]int64)
+	resultType := types.Type{Oid: types.T_datetime, Size: 8}
+	resultElementSize := int(resultType.Size)
+	if firstVector.IsScalar() {
+		if firstVector.ConstVectorIsNull() {
+			return proc.AllocScalarNullVector(resultType), nil
+		}
+		resultVector := vector.NewConst(resultType)
+		resultValues := make([]types.Datetime, 1)
+		vector.SetCol(resultVector, date_sub.DatetimeSub(firstValues, secondValues, thirdValues, resultValues))
+		return resultVector, nil
+	} else {
+		resultVector, err := proc.AllocVector(resultType, int64(resultElementSize*len(firstValues)))
+		if err != nil {
+			return nil, err
+		}
+		resultValues := encoding.DecodeDatetimeSlice(resultVector.Data)
+		resultValues = resultValues[:len(firstValues)]
+		nulls.Set(resultVector.Nsp, firstVector.Nsp)
+		vector.SetCol(resultVector, date_sub.DatetimeSub(firstValues, secondValues, thirdValues, resultValues))
+		return resultVector, nil
+	}
+}
diff --git a/pkg/sql/plan2/function/buitins.go b/pkg/sql/plan2/function/buitins.go
index fc8ba7f04ec60b70bf13030fef74fe18b5f6f34e..7a38ec2335afd7b819382e2a73b58ce001adfb46 100644
--- a/pkg/sql/plan2/function/buitins.go
+++ b/pkg/sql/plan2/function/buitins.go
@@ -1581,7 +1581,17 @@ var builtins = map[int][]Function{
 			Args:        []types.T{types.T_date, types.T_int64, types.T_int64},
 			ReturnTyp:   types.T_date,
 			TypeCheckFn: strictTypeCheck,
-			Fn:          nil,
+			Fn:          unary.DateAdd,
+		},
+		{
+			Index:       1,
+			Volatile:    true,
+			Flag:        plan.Function_STRICT,
+			Layout:      STANDARD_FUNCTION,
+			Args:        []types.T{types.T_datetime, types.T_int64, types.T_int64},
+			ReturnTyp:   types.T_datetime,
+			TypeCheckFn: strictTypeCheck,
+			Fn:          unary.DatetimeAdd,
 		},
 	},
 	DATE_SUB: {
@@ -1593,7 +1603,17 @@ var builtins = map[int][]Function{
 			Args:        []types.T{types.T_date, types.T_int64, types.T_int64},
 			ReturnTyp:   types.T_date,
 			TypeCheckFn: strictTypeCheck,
-			Fn:          nil,
+			Fn:          unary.DateSub,
+		},
+		{
+			Index:       1,
+			Volatile:    true,
+			Flag:        plan.Function_STRICT,
+			Layout:      STANDARD_FUNCTION,
+			Args:        []types.T{types.T_datetime, types.T_int64, types.T_int64},
+			ReturnTyp:   types.T_datetime,
+			TypeCheckFn: strictTypeCheck,
+			Fn:          unary.DatetimeSub,
 		},
 	},
 	TAN: {
diff --git a/pkg/sql/unittest/datatype_test.go b/pkg/sql/unittest/datatype_test.go
index 1a8dc3a822123e585459fcfadc09579e0d73ee3c..76357ed965b4e96615b7c711fa387d0f3842e6c8 100644
--- a/pkg/sql/unittest/datatype_test.go
+++ b/pkg/sql/unittest/datatype_test.go
@@ -246,7 +246,7 @@ func TestDatetimeType(t *testing.T) {
 		{sql: "select * from tbl2;", res: executeResult{
 			attr: []string{"a"},
 			data: [][]string{
-				{"2018-04-28 10:21:15"}, {"2017-04-28 03:05:01"}, {"2025-07-16 16:39:58"}, {"2021-12-03 14:56:33"}, {"null"},
+				{"2018-04-28 10:21:15.123000"}, {"2017-04-28 03:05:01.456000"}, {"2025-07-16 16:39:58.567000"}, {"2021-12-03 14:56:33.890000"}, {"null"},
 			},
 		}, com: "that is disputed. what does the msec do?"},
 		{sql: "select * from tbl3;", res: executeResult{
diff --git a/pkg/vectorize/date_add/date_add.go b/pkg/vectorize/date_add/date_add.go
new file mode 100644
index 0000000000000000000000000000000000000000..a9a5dad49ccb18980d246828ba92866965c94f6e
--- /dev/null
+++ b/pkg/vectorize/date_add/date_add.go
@@ -0,0 +1,40 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package date_add
+
+import "github.com/matrixorigin/matrixone/pkg/container/types"
+
+var (
+	DateAdd     func([]types.Date, []int64, []int64, []types.Date) []types.Date
+	DatetimeAdd func([]types.Datetime, []int64, []int64, []types.Datetime) []types.Datetime
+)
+
+func init() {
+	DateAdd = dateAdd
+	DatetimeAdd = datetimeAdd
+}
+
+func dateAdd(xs []types.Date, ys []int64, zs []int64, rs []types.Date) []types.Date {
+	for i, d := range xs {
+		rs[i] = d.ToTime().AddInterval(ys[i], types.IntervalType(zs[i])).ToDate()
+	}
+	return rs
+}
+
+func datetimeAdd(xs []types.Datetime, ys []int64, zs []int64, rs []types.Datetime) []types.Datetime {
+	for i, d := range xs {
+		rs[i] = d.AddInterval(ys[i], types.IntervalType(zs[i]))
+	}
+	return rs
+}
diff --git a/pkg/vectorize/date_add/date_add_test.go b/pkg/vectorize/date_add/date_add_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..72b4bf9dc72fb6daddf69898096982944b6c7934
--- /dev/null
+++ b/pkg/vectorize/date_add/date_add_test.go
@@ -0,0 +1,83 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package date_add
+
+import (
+	"testing"
+
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/stretchr/testify/require"
+)
+
+func TestDateAdd(t *testing.T) {
+	testCases := []struct {
+		name  string
+		args1 []types.Date
+		args2 []int64
+		args3 []int64
+		want  []types.Date
+	}{
+		{
+			args1: []types.Date{types.FromCalendar(2021, 8, 13)},
+			args2: []int64{1},
+			args3: []int64{int64(types.Day)},
+			want:  []types.Date{types.FromCalendar(2021, 8, 14)},
+		},
+		{
+			args1: []types.Date{types.FromCalendar(2021, 1, 31)},
+			args2: []int64{1},
+			args3: []int64{int64(types.Month)},
+			want:  []types.Date{types.FromCalendar(2021, 2, 28)},
+		},
+	}
+
+	for _, c := range testCases {
+		t.Run(c.name, func(t *testing.T) {
+			got := make([]types.Date, len(c.args1))
+			require.Equal(t, c.want, dateAdd(c.args1, c.args2, c.args3, got))
+		})
+	}
+
+}
+
+func TestDatetimeAdd(t *testing.T) {
+	testCases := []struct {
+		name  string
+		args1 []types.Datetime
+		args2 []int64
+		args3 []int64
+		want  []types.Datetime
+	}{
+		{
+			args1: []types.Datetime{types.FromClock(2020, 1, 1, 1, 1, 1, 1)},
+			args2: []int64{1},
+			args3: []int64{int64(types.MicroSecond)},
+			want:  []types.Datetime{types.FromClock(2020, 1, 1, 1, 1, 1, 2)},
+		},
+		{
+			args1: []types.Datetime{types.FromClock(2020, 1, 1, 1, 1, 1, 1)},
+			args2: []int64{1},
+			args3: []int64{int64(types.Second)},
+			want:  []types.Datetime{types.FromClock(2020, 1, 1, 1, 1, 2, 1)},
+		},
+	}
+
+	for _, c := range testCases {
+		t.Run(c.name, func(t *testing.T) {
+			got := make([]types.Datetime, len(c.args1))
+			require.Equal(t, c.want, datetimeAdd(c.args1, c.args2, c.args3, got))
+		})
+	}
+
+}
diff --git a/pkg/vectorize/date_sub/date_sub.go b/pkg/vectorize/date_sub/date_sub.go
new file mode 100644
index 0000000000000000000000000000000000000000..408850434d06155ea4f85b695ae27eb84e87efa9
--- /dev/null
+++ b/pkg/vectorize/date_sub/date_sub.go
@@ -0,0 +1,40 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package date_sub
+
+import "github.com/matrixorigin/matrixone/pkg/container/types"
+
+var (
+	DateSub     func([]types.Date, []int64, []int64, []types.Date) []types.Date
+	DatetimeSub func([]types.Datetime, []int64, []int64, []types.Datetime) []types.Datetime
+)
+
+func init() {
+	DateSub = dateSub
+	DatetimeSub = datetimeSub
+}
+
+func dateSub(xs []types.Date, ys []int64, zs []int64, rs []types.Date) []types.Date {
+	for i, d := range xs {
+		rs[i] = d.ToTime().AddInterval(-ys[i], types.IntervalType(zs[i])).ToDate()
+	}
+	return rs
+}
+
+func datetimeSub(xs []types.Datetime, ys []int64, zs []int64, rs []types.Datetime) []types.Datetime {
+	for i, d := range xs {
+		rs[i] = d.AddInterval(-ys[i], types.IntervalType(zs[i]))
+	}
+	return rs
+}
diff --git a/pkg/vectorize/date_sub/date_sub_test.go b/pkg/vectorize/date_sub/date_sub_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..3a08fa87742dc6aa5f758ac6b11ff1ef11c75902
--- /dev/null
+++ b/pkg/vectorize/date_sub/date_sub_test.go
@@ -0,0 +1,83 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package date_sub
+
+import (
+	"testing"
+
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/stretchr/testify/require"
+)
+
+func TestDateSub(t *testing.T) {
+	testCases := []struct {
+		name  string
+		args1 []types.Date
+		args2 []int64
+		args3 []int64
+		want  []types.Date
+	}{
+		{
+			args1: []types.Date{types.FromCalendar(2021, 8, 13)},
+			args2: []int64{1},
+			args3: []int64{int64(types.Day)},
+			want:  []types.Date{types.FromCalendar(2021, 8, 12)},
+		},
+		{
+			args1: []types.Date{types.FromCalendar(2021, 1, 1)},
+			args2: []int64{1},
+			args3: []int64{int64(types.Day)},
+			want:  []types.Date{types.FromCalendar(2020, 12, 31)},
+		},
+	}
+
+	for _, c := range testCases {
+		t.Run(c.name, func(t *testing.T) {
+			got := make([]types.Date, len(c.args1))
+			require.Equal(t, c.want, dateSub(c.args1, c.args2, c.args3, got))
+		})
+	}
+
+}
+
+func TestDatetimeSub(t *testing.T) {
+	testCases := []struct {
+		name  string
+		args1 []types.Datetime
+		args2 []int64
+		args3 []int64
+		want  []types.Datetime
+	}{
+		{
+			args1: []types.Datetime{types.FromClock(2020, 1, 1, 1, 1, 1, 1)},
+			args2: []int64{1},
+			args3: []int64{int64(types.MicroSecond)},
+			want:  []types.Datetime{types.FromClock(2020, 1, 1, 1, 1, 1, 0)},
+		},
+		{
+			args1: []types.Datetime{types.FromClock(2020, 1, 1, 1, 1, 1, 1)},
+			args2: []int64{2},
+			args3: []int64{int64(types.Second)},
+			want:  []types.Datetime{types.FromClock(2020, 1, 1, 1, 0, 59, 1)},
+		},
+	}
+
+	for _, c := range testCases {
+		t.Run(c.name, func(t *testing.T) {
+			got := make([]types.Datetime, len(c.args1))
+			require.Equal(t, c.want, datetimeSub(c.args1, c.args2, c.args3, got))
+		})
+	}
+
+}